该文章写的很好:https://zhuanlan.zhihu.com/p/342755411
Spring security 分为两个部分
- 登陆认证
- 权限认证
登陆认证
其实就是就是登陆注册,然后获取登陆凭证的问题
操作如下
- 登陆账号密码,通过账号查询出用户数据,然后密码进行比对
- 比对成功,将用户信息插入 SecurityContextHolder 中
SecurityContextHolder 有数据,UsernamePasswordAuthenticationFilter 就认为用户过了登陆认证,则不在登陆拦截
@AutoConfiguration
// 需要配置权限认证的其实就只有这一段,添加这个注解就OK了
// 就是这个 prePostEnabled=true,有了它,就可以在方法上写注解来做权限验证
// 例如:@PreAuthorize("@实例类.方法('参数')")
// example:@PreAuthorize("@ss.hasPermission('true')")
// 具体看下面的权限验证部分
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class YudaoWebSecurityConfigurerAdapter {
... 省略其他代码
/**
* 配置 URL 的安全配置
*
* 注意:
* 其实这里主要是设置是否需要登录的
* 权限验证其实不在这个地方
*
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
@Bean
protected SecurityFilterChain configure(HttpSecurity httpSecurity) throws Exception {
// 设置每个请求的权限
httpSecurity
// ①:全局共享规则
.authorizeRequests()
// permitAll 关键点 这里就是意思要不要登陆
.antMatchers(securityProperties.getPermitAllUrls().toArray(new String[0])).permitAll()
// ③:兜底规则,必须认证
.anyRequest().authenticated()
;
// 添加 JWT Filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
... 省略其他代码
权限验证
@AutoConfiguration
@EnableConfigurationProperties(SecurityProperties.class)
public class YudaoSecurityAutoConfiguration {
@Resource
private SecurityProperties securityProperties;
/**
* Spring Security 加密器
* 考虑到安全性,这里采用 BCryptPasswordEncoder 加密器
*
* @see <a href="http://stackabuse.com/password-encoding-with-spring-security/">Password Encoding with Spring Security</a>
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 认证失败处理类 Bean
*/
@Bean
public AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPointImpl();
}
/**
* 权限不够处理器 Bean
*/
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedHandlerImpl();
}
/**
* Token 认证过滤器 Bean
*/
@Bean
public TokenAuthenticationFilter authenticationTokenFilter(GlobalExceptionHandler globalExceptionHandler) {
return new TokenAuthenticationFilter(securityProperties, globalExceptionHandler);
}
@Bean("ss") // 使用 Spring Security 的缩写,方便使用
public SecurityFrameworkService securityFrameworkService() {
return new SecurityFrameworkServiceImpl();
}
}
权限验证
上面配置已经开启了注解 @PreAuthorize 来做权限验证
看懂这里就简单了。举例如下
例如:@PreAuthorize(“@实例类.方法(‘参数’)”)
example:@PreAuthorize(“@ss.hasPermission(‘true’)”)
这里实现就是:
- 开启注解@PreAuthorize做权限校验
- 注入名称为 ss 的bean
- 写入方法 hasPermission,方法返回true=权限校验通过,false=权限校验不通过
注入名称为 ss 的bean 如下:
// 创建一个权限校验类
@AllArgsConstructor
public class SecurityFrameworkServiceImpl {
@Override
public boolean hasPermission(String permission) {
return permission.equals("true");
}
@Override
public boolean hasAnyPermissions(String... permissions) {
return false;
}
@Override
public boolean hasRole(String role) {
return false;
}
@Override
public boolean hasAnyRoles(String... roles) {
return false;
}
@Override
public boolean hasScope(String scope) {
return false;
}
@Override
public boolean hasAnyScopes(String... scope) {
return false;
}
}
// 实例化 权限校验类,并注入spring容器中
@Bean("ss")
public SecurityFrameworkService securityFrameworkService() {
return new SecurityFrameworkServiceImpl();
}
到这里就结束了!
@PreAuthorize(“@ss.hasPermission(‘true’)”)
@PreAuthorize 开启校验
调用ss实例类中的hasPermission方法
返回结果为true=权限通过,false=权限不通过