发表于: 2018-09-10 19:31:36
1 505
spring security的鉴权,分为放权限用户信息和进行信息的比对两个部分,使用的基本方法如下;
在configureGlobal方法里,spring security通过AuthenticationManagerBuilder的inMemoryAuthentication()方法实例化AbstractDaoAuthenticationConfigurer,并初始化其属性userDetailsService和DaoAuthenticationProvider provider,向provider中注入了新创建的空的userDetailsService ,
但随即就通过withUser和password创建了一个UserDetailsBuilder,这里头记录了用户信息,再用initUserDetailsService将这个用户信息关联到provider的userDetailsService中。至此完成存放的工作。
Spring security通过AuthenticationManager这个全局认证管理器在用户登录认证时的过滤链中触发,但认证委托给继承类ProviderManager,而真正执行认证的是这个类下面的一个属性List<AuthenticationProvider> providers, 我们又看到了这个provider,进一步发现,AuthenticationProvider就是DaoAuthenticationProvider的顶层父级接口类,因此在用List<AuthenticationProvider> providers进行认证时,就是在用DaoAuthenticationProvider provider,因此就可以获取到里面设定的用户信息了。
真正执行鉴权的是ProviderManager的authenticate方法进行鉴权;
四种类型的创建用户,jdbc,ldap,内存中,自定义;jdbc是用的原始jdbc语句来进行,想想还是算了,ldap是不太合适,数据库的验证,得用自定义的userDetailsService,传入AuthenticationManagerBuilder就可以了,之前是直接放在内存中,看了个分析源码,底层也是userDetailsService,所以核心就是这个,通过传入的use信息;
userDetails有关的类有几个,自己捋了下作用;
user--security中的用户必须的信息,包括name,password,roles,账号过期,凭证过期,账户未锁定这几个属性;其中如果哪个属性缺失,会采用默认值;最少有前三个,就像之前在内存中放的一样;
userDetail为user的接口,
userDetailsService是一个接口,集中鉴权方式,都需要实现这个接口,作用是通过name加载userDetails的实现类;即user或者自定义的user;
UserDetailsManager--用来对userDetail进行管理,包括创建,更新,删除,改密码,判断存在等等;
UserDetailsBuilder--具体的进行user创建的类;
这几个的关系,自己没捋完,捋完日报来个图补下,目前的思考他们的内在逻辑,跟dao,service这种差不多,多层调用这种的。。
spring自己并不提供用户权限及角色控制之间的关系,而是需要用户自己去设计权限资源和用户角色的相关度等等,可以进行简单配置,也可以自己弄个复杂的设置,在Spring Security的使用中,有4种方法,有简单的有复杂的:
- 一种是全部利用配置文件,将用户、权限、资源(url)硬编码在配置文件(xml,java代码等形式)中;
- 二种是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置。
- 三种是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器 并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。
- 四是修改spring security的源代码,主要是修改InvocationSecurityMetadataSourceService和UserDetailsService两个类。 前者是将配置文件 或数据库中存储的资源(url)提取出来加工成为url和权限列表的Map供Security使用,后者提取用户名和权限组成一个完整的(UserDetails)User 对象,该对象可以提供用户的详细信息供AuthentationManager进行认证与授权使用。
之前的跑的小demo是算第一种,本来今天打算弄第三种的,然后看了下他的配置,不是用mybatis配置的,有点不好弄,找的一个mybatis弄的例子,应该算第二种,先实现了下;逻辑搞的差不多再弄第三种比较通用的模式;
如果要使用数据库的权限管理及用户限制,就需要重写userDetailsService方法;可以看到方法里查到的user,即之前简单配置里的那几个信息,username,password,role这个三个东西,其实不算全;
public class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口
@Autowired
UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) { //重写loadUserByUsername 方法获得 userdetails 类型用户
SysUser user = userDao.findByUserName(username);
if(user == null){
throw new UsernameNotFoundException("用户名不存在");
}
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
//用于添加用户的权限。只要把用户权限添加到authorities 就万事大吉。
for(SysRole role:user.getRoles())
{
authorities.add(new SimpleGrantedAuthority(role.getName()));
System.out.println(role.getName());
}
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), authorities);
}
}
权限表弄了三张,
他的mapper文件是联表查询;
<select id="findByUserName" parameterType="String" resultMap="userMap">
select u.*
,r.name
from Sys_User u
LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id
LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id
where username= #{username}
</select>
也得研究下;那个三个表的那个,肯定也是这样的。。
configure文件如下;硬编码权限,数据库放信息--最终要实现两个都放在数据库中算完成。。。
http
.csrf().disable()//关闭csrf认证
.authorizeRequests() //任何请求所有认证
// .anyRequest().permitAll()
.antMatchers("/s/user/**").hasRole("USER")
.antMatchers("/s/admin/**").hasRole("ADMIN")
.and()
.formLogin()// 表单登录
.loginProcessingUrl("/denglu") // 登录 Action 的 URI
.loginPage("/denglu") // 登录页面 URI
.failureForwardUrl("/error") // 登录失败后的页面URI
.and().logout().permitAll();
// http.authorizeRequests().anyRequest().permitAll();//任何请求不用认证
}
@Bean
UserDetailsService customUserService(){ //注册UserDetailsService 的bean
return new CustomUserService();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.inMemoryAuthentication().withUser("admin").password("{noop}123456").roles("ADMIN")
// .and().withUser("user").password("{noop}123456").roles("USER");
auth.userDetailsService(customUserService()); //user Details Service验证
}
明天计划:摸透简单的,搞复杂的逻辑;
评论