1. 认证组件列表
-
SecurityContextHolder
存储认证过的用户的详细信息 -
SecurityContext
包含在SecurityContextHolder
中, 存储当前已认证用户的信息(Authentication
对象) -
Authentication
提供给AuthenticationManager
以提供用户凭证(密码), 或者当前用户 -
GrantedAuthority
授予用户的权限. -
AuthenticationManager
决定调用哪个身份认证过滤器 -
ProviderManager
AuthenticationManager
最常用的实现. -
AuthenticationEntryPoint
用来向客户端请求凭证(如重定向到登录页面, 或返回一个www-authenticate响应) -
AbstractAuthenticationProcessingFilter
用于进行认证的基本Filter.
2. SecutiryContextHolder
SecutiryContextHolder
用于存储已认证用户的信息, 它不关心用户是如何通过认证的, 只要包含一个值, 则这个值将被用来作为一个已认证用户. 这是一个jvm设置, 因此其所有方法都是静态的.
通过配置指定相关策略. 其实现被委托给 SecurityContextHolderStrategy
. 策略指定有两种方法, 一种是系统属性, 一种是调用静态方法.
其策略有三种:
- ThreadLocal:
默认, 使用一个ThreadLocal来存储用户信息, 因此在同一个线程中可以获取到用户信息. - InheritableThreadLocal:
使用一个InheritableThreadLocal存储用户信息, 可以当前线程创建的子线程中也可以获取到用户信息. - Global:
全局共享一个SecurityContext
.
获取用户信息:
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
类图:
3. SecurityContext
存储Authentication对象.
4. Authentication
在成功调用AuthenticationManager.authenticate(Authentication)
方法后, 用于存储已认证用户的信息.
如果其authenticated
属性值为false, Spring Security都将会对其进行验证.
Collection extends GrantedAuthority> getAuthorities()
用于获取授予认证主体的权限, 当没有权限时应返回空集合,而不是null.
Object getDetails()
方法用于存储认证请求信息, 如IP地址, 凭证序列号等.
Object getPrincipal()
: 在使用用户名和密码登录验证的请求中, 在认证成功之前, 这通常是用户名, 认证成功后, 这通常是一个UserDetails对象.
boolean isAuthenticated()
: 用于指示AbstractSecurityInterceptor
是否将当前的Authentication对象传递给AuthenticationManager
进行身份验证.
5. GrantedAuthority
用于表示用户所获取的权限, 如角色. 如果使用用户名密码认证, 权限应由UserDetailsService
加载.
它用字符串来表示, 以便能进行精确匹配.
6. AuthenticationManager
用于处理认证请求. 认证后会将用户信息存储到SecurityContext中. 其最常用的实现为ProviderManager
.
必须对以下异常进行验证:
- 如果用户被禁用,则应抛出
DisabledException
. - 如果用户被锁定, 则应抛出
LockedException
. - 如果凭证错误, 则必须抛出badcredentialexception。
Authentication authenticate(Authentication authentication) throws AuthenticationException
: 如果调用成功则返回一个完全填充(包含了较全面的用户信息)的Authentication对象.
7. ProviderManager
最常用的AuthenticationManager
实现. 它包含一个AuthenticationProvider
集合. 每个provider对应一种身份验证方式, 因此通过AuthenticationManager
可以支持多种身份验证方式. 如果请求没有相应的provider, 则将抛出ProviderNotFoundException
.
ProviderManager遍历每个provider, 如果有一个provider返回非null结果, 则将不再调用后续未调用的provider.
此外, ProviderManager还可以配置一个parent, 当ProviderManager无法进行认证时, 可以调用这个parent. 这样可以在有多个ProviderManager实例时, 通过parent来处理公共认证方式. parent可以是任何AuthenticationManager
实例, 但通常为ProviderManager
.
ProviderManager还负责在认证成功后清除用户凭证(密码). 其eraseCredentialsAfterAuthentication
属性值默认为true. 这对于通过缓存用户信息再进行认证的场景可能有影响(因为密码被清除了). 解决方式是设置eraseCredentialsAfterAuthentication
为false.
认证事件
可通过AuthenticationEventPublisher
来发布认证事件(成功,失败). 默认是一个Null实现(不发布事件). 因此如果需要发布事件,则需要注入对应的bean(DefaultAuthenticationEventPublisher
). ProviderManager的parent通常不需要配置publisher, 因为manager可以对parent的认证结果发布相应的事件, 从而造成事件 的重复发布.
AuthenticationManager类图:
7. AuthenticationProvider
定义认证方式.
8. AuthenticationEntryPoint
在ExceptionTranslationFilter
中用来定义认证方案. 即返回给客户端响应以要求客户端提供何种方式的认证.
类图:
9. AbstractAuthenticationProcessingFilter
身份验证的一个基础Filter.
- 用户提交认证请求后, 它将从请求中获取相关参数并创建一个
Authentication
对象(对象类型取决于其实现类). - Authentication对象被传递给
AuthenticationManager
进行验证处理. - 如果验证不通过, 将清除
SecurityContextHolder
; 调用RememberMeService.loginFail
(如果配置了remeberme); 调用AuthenticationFailureHandler
. 如果验证通过, 通知SessionAuthenticationStrategy
有一个新的登录; 存储Authentication
到SecurityContextHolder
,SecurityContextPersistenceFilter
保存这个SecurityContext
到HttpSession
; 如果配置了remeberme, 调用RemeberMeService.loginSuccess
;ApplicationEventPublisher
发布一个InteractiveAuthenticationSuccessEvent
, 调用AuthenticationSuccessHandler
.
类图: