Spring Boot Security 介绍
-
Spring Security 是通过一层层 Filter 来处理 web 请求的
在 Filter 组成的链条中,逐步完成认证和授权,发现异常则抛给异常处理器处理
-
过滤器链中的核心概念
springSecurityFilterChain
Spring Security 的核心过滤器叫 springSecurityFilterChain,类型是 FilterChainProxyWebSecurity、HttpSecurity
WebSecurity 构建了 FilterChainProxy 对象
HttpSecurity 构建了 FilterChainProxy 中的一个 SecurityFilterChainWebSecurityConfiguration
@EnableWebSecurity 注解,导入了 WebSecurityConfiguration 类
WebSecurityConfiguration 中创建了建造者对象 WebSecurity 和核心过滤器 FilterChainProxy -
Spring Security 常用组件
Authentication:认证接口,定义了认证对象的数据形式。
SecurityContext:上下文对象,用来存储 Authentication
SecurityContextHolder:用来访问 SecurityContext
UserDetails:代表用户信息
UserDetailsService:获取用户信息
一、前期环境搭建
我的测试用户Entiy结构是这样的
public class SchoolUser {
private String userName;
private String passWord;
private List<SchoolUserRoles> roles;
}
---------------
public class SchoolUserRoles {
private String coleName;
private String coleCode;
private List<SchoolUserPermission> permissions;
}
----------------
public class SchoolUserPermission {
//权限名
private String code;
//权限类型
private String type;
//资源路径
private String url;
}
以及一些Controller,具体代码以上传至码云(地址见文章末尾)
二、使用步骤
1.配置自己的UserDetailService规则
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
//用来模拟数据库操作
@Autowired
private AuthenticationMapper authenticationMapper;
//用于通过用户名获取用户数据. 返回 UserDetails 对象, 表示用户的核心信息 (用户名, 用户密码, 权限等信息)
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//因为这里我使用的模拟数据,密码没有加密过,需要手动加密
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
SchoolUser schoolUser = authenticationMapper.findRolesBySchoolUserName(s);
if(null == schoolUser){
throw new UsernameNotFoundException(s);
}
ArrayList<SimpleGrantedAuthority> authorities = new ArrayList<>();
//获取角色
for (SchoolUserRoles role : schoolUser.getRoles()) {
//获取角色实际资源
for (SchoolUserPermission permission : role.getPermissions()) {
authorities.add(new SimpleGrantedAuthority(permission.getCode()));
}
}
return new User(schoolUser.getUserName(),passwordEncoder.encode(schoolUser.getPassWord()),authorities);
}
}
2.Security配置类
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法级别设置
public class MySecurity extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
//路径权限设置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
/*
因为使用了方法级别权限设置,就不在这里设置拦截了
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2")
.antMatchers("/level3/**").hasRole("vip3")
*/
.antMatchers("/","/index","*.js","*.css").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().logoutUrl("/logout").logoutSuccessUrl("/index")
.and()
.csrf().disable();
}
//认证授权(赋予角色)
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(getBCryptPasswordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
//静态资源过滤
/*
* 如果不进行静态资源过滤的话,点击登录按钮会因为加载js文件需要权限跳转到登录
* 然后登录通过之后,因为Security默认是登录完成后,到达登录前没有权限的页面,所以会打开该js文件
* */
web.ignoring().antMatchers("/qinjiang/**");
}
@Bean
public BCryptPasswordEncoder getBCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
3 路径设置
@PreAuthorize("hasAuthority('vip1')")
@RequestMapping("/level1/1")
public String level(){
return "/views/level1/1";
}
/*
@PreAuthorize()内有许多方法可以设置权限
hasRole 用户具备某个角色( 这里内部拼接ROLE_,所以如果想自定义角色,请加上ROLE_ )
hasAuthority 类似与hasRole
hasAnyRole 用户具备多个角色中任意一个即可
hasAnyAuthority 类似于hasAnyRole
... 这里不多讨论了
*/
//权限中必须有Vip2这个权限
@PreAuthorize("hasAuthority('vip2')")
@RequestMapping("/level2/1")
public String level_1(){
return "/views/level2/1";
}
这里就简单使用了SpringBoot Security完成权限设置以及授权
源码地址
源代码地址: https://gitee.com/crazyheng/spring-boot-security
有些人可能一开始对于Role与Permission权限有点疑惑,只要记清楚一个要点:真实控制资源路径的还是权限,然后角色控制权限,再给用户赋予角色,从而达到权限控制,权限都是为了真实资源而服务的,不管怎么变,最终都是对真实资源进行设置。
总结
这只是简单的使用Security,接下我准备了解学习下,UserDetailService的底层工作流程,Security认证流程,以及@EnableGlobalMethodSecurity与@PreAuthorize等,在这里就不多讨论了,请读者自行网络学习源码了解。