用户认证问题,分为首次登陆,和二次认证。
-
首次登录认证:用户名、密码和验证码完成登录
-
二次 token 认证:请求头携带 Jwt 进行身份认证
一、前后台分离登录校验流程
流程:
- 前端携带用户名,密码访问登录接口
- 后端查询数据库,验证是否登录成功。如果正确,生成一个token
- 后端把token响应给前端
- 前端登录之后的访问请求接口,需要在请求头中携带token
- 后端获取请求头token,进行解析,获取UserId,根据Userd获取用户相关信息,如果有权限,则允许访问相关资源访问目标资源,响应给前端
二、SpringSecurity的认证流程
本质
SpringSecurity采用的是责任链设计模式, 本质是一个过滤器链。
责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。
在这种模式中,通常每个接收者都包含对另一个接收者的引用,而连接起来形成一条链。
请求在这个链上传递,直到链上的某一个对象决定处理此请求。
如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
核心
SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。
图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示:
- UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。
- ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException 。
- FilterSecurityInterceptor:负责权限校验的过滤器。我们可以通过Debug查看当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。
我们也可以通过debug,查看SpringSecurity的过滤器链:
在我们的启动类添加对应的断点
在引入Spring Security依赖之后开发者不做任何配置时Spring Security会为我们加载一部分过滤器:
-
SecurityContextPersistenceFilter:在请求处理之前将安全信息加载到SecurityContextHolder中方便后续使用。请求结束后,在擦除SecurityContextHolder中的信息。
-
CsrfFilter:处理CSRF攻击
-
LogoutFilter:处理注销登录
-
UsernamePasswordAuthenticationFilter :处理填写了用户名密码的登陆请求——从表单中获取用户名密码,并进行身份验证。
-
DefaultLoginPageGeneratingFilter:配置默认登录页面
-
DefaultLogoutPageGeneratingFilter:配置默认注销页面
-
BasicAuthenticationFilter:处理HttpBasic登录
-
ExceptionTranslationFilter :异常过滤器,捕获过滤器链抛出的异常并进行处理,主要处理AccessDeniedException 和AuthenticationException 异常。
-
FilterSecurityInterceptor:根据资源权限配置来判断当前请求是否有权限访问对应的资源,如果访问受限会抛出相关异常,并由ExceptionTranslationFilter 过滤器进行捕获和处理。是过滤器链的最后一个过滤器,是过滤器链的出口。
…
认证流程详解
- Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。
- AuthenticationManager接口:定义了认证Authentication的方法
- UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。
- UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
修改为自定义认证流程
思路分析
登录:
自定义登录接口
调用ProviderManager的authenticate()方法进行认证,如果认证通过,则生成JWT
把用户信息存入redis中
自定义UserDetailsService接口实现类
我们在这个实现类查询数据库
校验:
定义JWT认证过滤器
获取token
解析token获取其中的uuid
从redis中获取用户信息
存入SecurityContextHolder
总结
从基本认证流程中不难看出,我们可以重写或者替换UsernamePasswordAuthenticationFilter过滤器,用以添加我们需要的业务处理逻辑,并且可以实现UserDetailsService接口,加入Spring Data JPA或者Mybatis用来访问数据库中的用户信息