概述
Spring Security 是 Spring 在安全方面的推出的框架,是采用责任链的设计模式,基于 Spring AOP 和 Servlet 过滤器进行实现。这篇文章记录认证授权的一些概念,以及如何使用其进行扩展保护我们的应用。
认证与授权的概念
- 认证:
我是谁
- 授权:
有哪些访问权限
在系统安全方面,我们面临的两个问题是:
1、如何保护需要访问权限的资源?
在 Java 中我们一般使用过滤器对我们的资源进行保护,使用拦截器对方法的访问进行控制。
2、用户的登录状态要如何传递?
如何让服务器意识到用户已经登录过系统了?一种是使用 Session 进行认证,令一种是使用 Token (令牌) 进行认证。
Session 认证
这种认证方式的缺点是:一是不能用于移动端的认证,二是一旦客户禁用浏览器 Cookie 将会导致无法认证。以下是基于 Session 认证的流程:
用户密码登录 --> 服务器验证通过,为用户创建一个Session(服务器中的一小块内存区域),存储登录用户信息
--> 返回 SessionID,写入用户Cookie --> Cookie将与每个后续请求一起发送 --> 将SessionID与服务器中的信息进行比对
Token 认证
- 自定义 Token
我们可以在用户认证成功后生成自定义令牌,保存在Redis或者内存中,返回给前端,用户后续的每次请求都在在请求头 Authorization 中携带令牌,而不是将认证信息存放在请求头 Cookie 中。之后我们将请求头中的令牌与服务器存储的令牌进行比较,验证用户的登录状态。
-
JWT(JSON Web Tokens)
:
另外一种方案是使用 JWT。
优点:1、无需对Token
进行存储,可以直接通过计算进行校验,以时间换空间。2、可以在 Token 中存储用户的相关信息
缺点:Token 无法随时废弃。
Spring Security 配置
Spring Security 是一款高度可配置化的框架,我们可以继承或者实现相关的类,从而实现定制化功能。以下是配置的一个示例:
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthSuccessHandler authSuccessHandler;
private final AuthFailureHandler authFailureHandler;
private final SimpleAccessDeniedHandler accessDeniedHandler;
private final SimpleAuthenticationEntryPoint authenticationEntryPoint;
private final JwtProperties jwtProperties;
/**
* 配置不需要进行认证的接口
*/
@Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/css/**")
.antMatchers("/signUp.html")
.antMatchers("/user/**")
.antMatchers("/common/test")
.antMatchers("/test");
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login.html")
.loginProcessingUrl("/login")
.successHandler(authSuccessHandler)
.failureHandler(authFailureHandler)
.permitAll()
.and()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/login.html").permitAll()
//开启认证
.anyRequest().authenticated()
.and().csrf().disable()
//前后端分离采用JWT 不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
//添加自定义权限过滤器
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
.addFilter(new JwtAuthorizationFilter(authenticationManager(), jwtProperties.getSecretKey()));
}
}
简单总结下,通过上面的代码,可以看出,我们可以做以下的一些配置:
1、配置不需要进行认证的路径
2、添加过滤器,可以自定义 Token 认证逻辑,主要是通过继承:BasicAuthenticationFilter,重写认证方法
3、自定义一些处理器:
- 认证成功处理器:在认证成功后需要什么后续的处理?比如:向前端返回JSON 数据,主要通过实现 AuthenticationSuccessHandler 接口
- 认证失败处理器:认证失败该做什么处理?如:返回自定义认证失败信息,在前后端分离的情况下,可以返回认证失败的 JSON 数据给前端,主要通过实现 AuthenticationFailureHandler 接口
4、访问需要权限的资源,未授权时要怎么对异常进行处理?可以抛出一些更家友好的提示等:主要实现:AuthenticationEntryPoint 接口
5、权限不足异常处理,如:前后端分离情况下,可以自定义返回 JSON 数据,主要通过实现:SimpleAccessDeniedHandler 接口
6、从哪里获取用户信息?我们可以实现:UserDetailsService 接口,实现 loadUserByUsername
方法,让程序从数据库当中获取我们的数据。
最后
所涉及的代码可以点击这里
参考链接
个人博客:https://www.kangpeiqin.cn/#/index