
#冲刺创作新星#SpringSecurity认证流程分析 原创
SpringSecurity认证流程分析
AuthenticationManager
AuthenticationManager是认证管理器 它定义了Spring Security过滤器要如何执行认证操作。AuthenticationManager在认证后会返回一个Authentication对象,它是一个接口,默认实现类是ProviderManager
AuthenticationProvider
AuthenticationProvider针对不同的身份类型执行具体的身份认证。
DaoAuthenticationProvider 用来支持用户名 密码登录认证
RememberMeAuthenticationProvider 用来支持记住我的认证
当用户使用用户名密码方式登录的时候,对应的AuthenticationProvider是DaoAuthenticationProvider,DaoAuthenticationProvider继承自AbstractUserDetailsAuthenticationProvider,认证时调用authenticate方法
AbstractUserDetailsAuthenticationProvider
重点看一下authenticate方法:首先从登录数据中获取用户名,根据用户名去缓存中查询用户对象,如果查询不到,则根据用户名调用retrieveUser方法从数据中加载用户;如果没有加载到用户,则抛出异常。拿到用户对象之后,首先调用preAuthenticationChecks.check方法进行用户状态检查,然后调用additionalAuthenticationChecks方法进行密码的校验操作,最后调用postAuthenticationChecks.check方法检查密码是否过期,当所有步骤都顺利完成后,调用createSuccessAuthentication创建一个认证后的UsernamePasswordAuthenticationToken对象并返回。
DaoAuthenticationProvider
DaoAuthenticationProvider 实现了AbstractUserDetailsAuthenticationProvider的抽象方法
主要是retrieveUser方法:获取用户对象的方法,具体做法是调用UserDetailsService的loadUserByUsername方法去数据库中查询。
ProviderMananger
ProviderMananger是AuthenticationManager的一个重要实现类。
- 首先获取authentication对象的模型
- 定义异常,认证结果等变量
- getProviders方法获取当前ProviderManager所代理的所有AuthenticationProvide对象,遍历这些AuthenticationProvider对象进行身份认证。
- 判断AuthenticationProvider是否支持当前Authentication,如果不支持,继续处理下一个AuthenticationProvider对象
- 调用provider.authenticate方法进行身份认证,如果认证成功,返回认证后的Authentication对象,同时调用copyDetails方法给Authentication对象的details属性赋值。对于可能是多个AuthenticationProvider执行认证操作,所以如果抛出异常,则通过lastException变量记录。
- 在for循环执行完成后,如果result还是没有值,说明所有的AuthenticationProvider都认证失败,此时如果parent不为空,则调用parent的authenticate方法进行认证。
- 如果result不为空,将result中的凭证擦擦,防止泄露。如果使用了用户名密码的方式登录,那么所谓的擦除就是将密码字段设置为null,同时将登录事件发布出去。
- 如果前面没能返回result,说明认证失败。如果lastException为null,说明parent为null或者没有认证或者认证失败了但没有抛出异常,此时构造ProviderNotFoundException赋值给lastException
- 如果parentResult为null,发布认证失败事件。
- 抛出lastException
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter是抽象类,如果使用用户名密码的方式登录,那么它对应的实现类是UsernamePasswordAuthenticationFilter,构造出来的Authentication是UsernamePasswordAuthenticationToken
- 首先通过requiresAuthentication方法来判断当前请求是不是登录认证请求,如果不是,直接走下一个过滤器
- 调用attemptAuthentication方法获取一个经过认证后的Authentication对象,attemptAuthentication是抽象方法,具体子类在UsernamePasswordAuthenticationFilter中。
- 认证成功后,通过sessionStrategy.onAuthentication方法来处理session并发问题。
- continueChainBeforeSuccessfulAuthentication表示继续下一个过滤器链,默认是false,即认证成功后不再执行下一个过滤器
- unsuccessfulAuthentication方法处理认证失败,主要做了三件事:
- SecurityContextHolder清除数据
- 处理Cookie
- 发布认证成功调用认证失败的回调方法
- successfulAuthentication方法处理认证成功,主要做了四件事:
- SecurityContextHolder存入用户信息
- 处理Cookie
- 发布认证成功事件
- 调用认证成功的回调方法。
AbstractAuthenticationProcessingFilter中的attemptAuthentication是UsernamePasswordAuthenticationFilter来实现的
UsernamePasswordAuthenticationFilter
attemptAuthentication 首先确认是post请求,然后获取用户名密码,构造authRequest 调用getAuthenticationManager().authenticate(authRequest)进行认证,即ProviderManager里的authenticate方法。
