Spring Security Note-6
认证流程源码详解
认证处理流程说明
当一个登录请求进入到过滤器链开始到整个认证完成;
1.发送登录请求,进入到UsernamePasswordAuthenticationFilter
的类中,它将用户名和密码封装成UsernamePasswordAuthenticationToken
的对象,设置认证状况为false,并且将请求的信息发送到details当中,接下来将进入到AuthenticationManager
;
2.AuthenticationManager
本身不参与认证的作用,它主要作为一个类似工具的作用,主要起到认证逻辑的对象是集合AuthenticationProvider
,对于不同的用户方式,它的认证逻辑是不同的,例如用户名+密码,微信;
3.不同的Provider支持的类型是不一样的,通过循环找到支持的类型;
4.通过UserDetailsService的逻辑,获得具体的UserDetails对象并返回;
5.做完预检查之后,还有一个附加检查,通过PasswordEncoder再次密码的校验,完成之后,最后有一个后检查,所有的检查通过之后,认为这个用户认证是成功的,就可以获取用户的信息;
6.将用户信息拼装,作为一个已认证的Authentication返回;
认证结果如何在多个请求之间共享
在完成认证的流程之后;
在调用认证成功处理器之前,有一个SecurityContextHolder.getContext().setAuthentication(authResult)
,它将完成认证的Authentication放入到SecurityContext当中;
在整个处理过程中,都能通过SecurityContextHolder读取已认证的Authentication;
SecurityContextPersistenceFilter在整个过滤器链请求的最前端,在响应的最后一端;
检查在Session中是否有SecurityContext,如果在Session中有,那么将取出来放入SecurityContextHolder当中,如果没有;
在线程SecurityContextHolder当中如果有SecurityContext,那么取出来放入Session当中;
获取认证用户信息
SecurityContextHolder获取认证用户的信息;
1 |
|
实现图形验证码功能
开发生成图形验证码接口
步骤:根据随机数生成图片;将随机数存到Session中;将生成的图片写到接口的响应中
1 | public class ImageCode { |
1 |
|
在认证流程中加入图形验证码校验
整合Spring Security校验,自定义一个Filter,将该Filter设置在UsernamePasswordAuthenticationFilter之前执行,这样就会在验证用户名密码之前就校验验证码;
1 | public class ValidateCodeFilter extends OncePerRequestFilter { |
1 |
|
重构代码
将图形验证码的基本参数配置,以三级模式的形式,层层覆盖;
上层是请求级配置
,配置值在调用接口时传递;
中层是应用级配置
,配置值在demo中,可被请求级覆盖;
下层是默认配置
,配置值在core中,可被应用级覆盖;
验证码基本参数可配置
1 | public class ImageCodeProperties { |
1 | public class ValidateCodeProperties { |
1 | "imooc.security") (prefix = |
1 |
|
验证码拦截接口可配置
1 | public class ImageCodeProperties { |
1 | public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean { |
1 |
|
1 | security.code.image.length=6 |
验证码生成逻辑可配置(以增量的方式,实现变化)
1 | public interface ValidateCodeGenerator { |
1 | public class ImageCodeGenerator implements ValidateCodeGenerator { |
1 |
|
“记住我”功能
1 | public class BrowserProperties { |
1 |
|
原理
用户发送认证请求到UsernamePasswordAuthenticationFilter
,当Spring Security认证成功之后,调用一个RememberMeService
的服务,这个服务里存在一个TokenRepository
,TokenRepository
会生成一个Token,并且将这个Token写入浏览器中的Cookie中,同时TokenRepository
将生成的Token与当前的用户身份,写入到数据库中;
当再次发送请求时,不需要重新登录,而是直接访问一个受保护的服务,这个请求不再走过滤器链中的UsernamePasswordAuthenticationFilter
,而是通过过滤器链中的RemberMeAuenticationFilter
去获取用户信息,直接读取Cookie中的Token给到RememberMeService
,TokenRepository
将会根据获取到的Token到数据库中查询对应的用户信息和Token是否匹配和存在;
如果有记录,就会把用户名取出来,取出来之后会调用UserDetailsService
,获取用户信息,然后把用户信息放入到SecurityContext
当中;