三、SpringSecurity登录过程源码分析

在这里插入图片描述
首先进入的是UsernamePasswordAuthenticationFilter这个过滤器,拿到登陆的用户名和密码生成一个UsernamePasswordAuthenticationToken的对象,查看继承图可以看到它是Authentication接口的一个实现,Authentication里面封装了用户的认证信息
在这里插入图片描述
在这里插入图片描述
这时调用的构造函数,将用户名密码设为本地变量principalcredentials,super调用父类的构造函数,因为此时并不知道用户有什么权限,所以为null
在这里插入图片描述
同样此时的身份信息也没有经过认证:setAuthenticated(false);
在这里插入图片描述
创建好UsernamePasswordAuthenticationToken对象之后,同时将请求信息也封装进去进入到getAuthenticationManager().authenticate(authRequest);
getAuthenticationManager()方法返回一个AuthenticationManager接口的实现类,跟进去authenticate()方法:
在这里插入图片描述
这是AuthenticationManager的一个实现类ProviderManager
在这里插入图片描述
在这个方法中,循环找出一个AuthenticationProvider的实现类,来调用实现类的authenticate方法来进行认证,不同的登陆方式所需要的AuthenticationProvider的实现类不同,所以这里要循环找出适合当前登陆方式的provider,这里使用的是DaoAuthenticationProvider
在这里插入图片描述
进入authenticate方法,首先来到的是DaoAuthenticationProvider的抽象父类
在这里插入图片描述
进入retrieveUser()方法:
在这里插入图片描述
在这里会拿到UserDetailsService的具体实现类,执行loadUserByUsername()方法
查看this.getUserDetailsService(),可以看到返回的就是我们自己写的实现类:UserLoginService,然后执行loadUserByUsername()方法返回User对象(实现了UserDetails接口的)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
AbstractUserDetailsAuthenticationProvider拿到返回的用户信息后,执行preAuthenticationChecks.check方法:检查三个布尔值认证信息
在这里插入图片描述
再执行additionalAuthenticationChecks,具体方法再其子类DaoAuthenticationProvider中实现,这里使用了passwordEncoder校验用户的密码,密码不匹配就抛出异常
在这里插入图片描述
接下来执行的是postAuthenticationChecks.check(user);,校验用户密码是否没有过期
在这里插入图片描述
在这里插入图片描述
所有认证完成后
在这里插入图片描述
在这里插入图片描述
这次调用的是UsernamePasswordAuthenticationToken三个参数的构造器,因为此时已经拿到了认证信息authoritiessuper.setAuthenticated(true)已经认证
这时AbstractUserDetailsAuthenticationProviderauthenticate方法,执行
createSuccessAuthentication返回一个经过认证的Authentication对象一步一步返回到UsernamePasswordAuthenticationFilter
然后会经过一个AbstractAuthenticationProcessingFilter,在这个抽象类中执行doFilter()方法
在这里插入图片描述
成功就执行成功的处理器,失败则执行失败的处理器
在这里插入图片描述
来到我们自己写的登陆成功的处理器
在这里插入图片描述
执行到这里,已经登陆成功,相应的登陆信息也返回给登陆请求。
下面看看不同的请求是如何拿到认证信息的(认证结果在不同的请求之间共享):
在这里插入图片描述
AbstractAuthenticationProcessingFilter中可以看到,在执行成功处理器之前,会执行SecurityContextHolder.getContext().setAuthentication(authResult);这个authResult就是包含了已登陆的用户授权信息的Authentication对象
SecurityContextHolder:Associates a given SecurityContext with the current execution thread.(将给定的SecurityContext与当前执行线程关联。)
SecurityContext:安全上下文,即存储认证授权的相关信息,实际上就是存储"当前用户"账号信息和相关权限。这个接口只有两个方法,获取和设置Authentication对象的getter、setter方法。

SecurityContextHolder使用了ThreadLocal机制来保存每个使用者的安全上下文。这意味着,只要针对某个使用者的逻辑执行都是在同一个线程中进行,即使不在各个方法之间以参数的形式传递其安全上下文,各个方法也能通过SecurityContextHolder工具获取到该安全上下文。SecurityContextPersistenceFilter是拦截链中的第一个拦截器,当一次请求结束时,这个过滤器会看当前线程上是否保存有SecurityContext,如果有则会被存到session中,sessionId被设置到cookie中,登陆之后的其他请求到来时,通过sessionId可以拿到session,把SecurityContext拿出来通过SecurityContextHolder放到当前线程中,从而在整个请求的流程中都可以拿到用户信息。

SecurityContextHolder获取用户信息:

/**
 * @auther Mr.Liao
 * @date 2019/8/20 9:38
 */
@RestController
public class SecurityContextHolderController {
    @GetMapping("getUserMsg")
    public Object getCurrentUser(){
        return SecurityContextHolder.getContext().getAuthentication();
    }
}

登陆之后访问接口:
在这里插入图片描述
也可以直接将Authentication对象作为方法的参数,在方法中使用

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值