导图社区 spring-security源码骨架
本图通过对spring security源码的剖析,将其中的认证流程、主要的认证服务进行展现,并对其中的一些方法做了说明,使读者可以非常容易的理解spring-security框架的处理过程
编辑于2022-03-04 11:49:34spring security
使用场景
框架源码骨架
核心过滤器:AbstractAuthenticationProcessingFilter
请求匹配策略规则: requiresAuthentication(request, response),决定是否要走权限相关校验
attemptAuthentication
根据登录方式确定具体子类
Cas登录
表单登录: UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationFilter是AbstractAuthenticationProcessingFilter针对使用用户名和密码进行身份验证而定制化的一个过滤器。其添加是在调用http.formLogin()时作用,默认的登录请求pattern为"/login",并且为POST请求。当我们登录的时候,也就是匹配到loginProcessingUrl,这个过滤器就会委托认证管理器authenticationManager来验证登录
UsernamePasswordAuthenticationFilter#attemptAuthentication
获取用户名密码
obtainUsername(request) obtainPassword(request) 默认取username和password属性,可进行重写,自定义传入的字段名称
设置用户自定义身份认证服务:setDetails
主要通过重写方法:loadUserByUsername
getAuthenticationManager().authenticate
在Spring Security中由于系统可能同时支持多种认证方式,,不同的认证方式对应不同的AuthenticationProvider,,因此在ProviderManager中存在一个AuthenticationProvider列表,ProviderManager会对列表中每一个AuthenticationProvider执行认证,最终得到认证结果,ProviderManager也可以配置一个parent,可以使任意类型的AuthenticationProvider,当列表中所有的AuthenticationProvider均认证不通过是,由parent认证。但通常都是由ProviderManager自己扮演parent
ProviderManager 实现接口:AuthenticationManager#authenticate
for: getProviders() 1. DaoAuthenticationProvider 2. AnonymousAuthenticationProvider
DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider # authenticate 可自定义继承DaoAuthenticationProvider
获取用户信息UserDetails
先从缓存中获取userCache.getUserFromCache(username)
缓存没有则通过:retrieveUser
DaoAuthenticationProvider#retrieveUser
getUserDetailsService().loadUserByUsername(username)
为之前:设置用户自定义身份认证服务:setDetails的地方设置的自定义方法
子主题
用户状态校验,校验用户的状态是否合法,比如是否被锁定,是否失效等:preAuthenticationChecks.check
默认实现: DefaultPreAuthenticationChecks
账号被锁定
抛出: LockedException
账号不可用
抛出: DisabledException
账号过期
抛出: AccountExpiredException
可自定义实现个性化校验规则
额外校验: additionalAuthenticationChecks,子类实现
DaoAuthenticationProvider#additionalAuthenticationChecks
后校验: postAuthenticationChecks.check(user)
Called by classes which make use of a UserDetailsService to check the status of the loaded UserDetails object. Typically this will involve examining the various flags associated with the account and raising an exception if the information cannot be used (for example if the user account is locked or disabled), but a custom implementation could perform any checks it wished. The intention is that this interface should only be used for checks on the persistent data associated with the user. It should not involved in making any authentication decisions based on a submitted authentication request.
由类调用,这些类使用UserDetailsService检查加载的UserDetails对象的状态。通常,这将涉及检查与帐户相关联的各种标志,并在信息无法使用(例如,如果用户帐户被锁定或禁用)时引发异常,但自定义实现可以执行它想要的任何检查。 其目的是,该接口只应用于检查与用户关联的持久数据。它不应参与根据提交的身份验证请求做出任何身份验证决定。
默认实现: DefaultPostAuthenticationChecks
缓存用户信息: userCache.putUserInCache(user)
创建成功校验信息: createSuccessAuthentication
创建成功的认证对象
protected方法,子类可重写自定义
异常处理
未获取到用户信息,抛出 BadCredentialsException
状态校验||额外校验异常
如果缓存中存在用户信息,则为了防止错误,会做二次校验
1. cacheWasUsed = false; 2. user =retrieveUser()
preAuthenticationChecks.check(user)
additionalAuthenticationChecks
缓存中不存在用户信息,则直接抛出异常
sessionStrategy.onAuthentication
异常处理
清理上下文:SecurityContextHolder.clearContext();
记住我处理: rememberMeServices.loginFail
失败处理器处理: failureHandler.onAuthenticationFailure
成功处理
成功处理器处理: successHandler.onAuthenticationSuccess
上下文处理: SecurityContextHolder.getContext().setAuthentication(authResult);
记住我处理: rememberMeServices.loginSuccess
成功处理器处理: successHandler.onAuthenticationSuccess
浮动主题