本文介绍 Spring Security 在 Servlet 认证中使用的主要架构组件。
目录
- SecurityContextHolder
- 设置身份认证信息
- 访问当前已通过身份认证的用户信息
- SecurityContext
- Authentication
- GrantedAuthority
- AuthenticationManager
- ProviderManager
- AuthenticationProvider
- 带有 AuthenticationEntryPoint 的请求凭证
- AbstractAuthenticationProcessingFilter
SecurityContextHolder
SecurityContextHolder
是 Spring Security 身份认证模型的核心,包含 SecurityContext
。
SecurityContextHolder
用于存储 Spring Security 已通过身份认证的用户详情。
Spring Security 并不关心如何填充 SecurityContextHolder
,如果它包含一个值,那么它将用作当前经过身份验证的用户。
设置身份认证信息
指示用户已通过身份验证的最简单方法是直接设置 SecurityContextHolder
:
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = new TestingAuthenticationToken("username", "password", "ROLE_USER");
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
说明:
- 创建一个空的
SecurityContext
对象。注意:如果直接调用SecurityContextHolder.getContext().setAuthentication(authentication)
不能避免多线程竞争; - 创建一个
Authentication
对象。Spring Security 并不关心设置给SecurityContext
的Authentication
对象的具体实现,这里使用TestingAuthenticationToken
是因为方便使用。生产环境中最常用的应该是UsernamePasswordAuthenticationToken(userDetails, password, authorities)
。 - 将
SecurityContext
设置给SecurityContextHolder
,Spring Security 将使用这些信息进行授权。
访问当前已通过身份认证的用户信息
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
String username = authentication.getName();
Object principal = authentication.getPrincipal();
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
默认情况下 SecurityContextHolder
使用 ThreadLocal
存储这些详情,这意味着 SecurityContext
始终可用于同一执行线程中的方法,即使没有将 SecurityContext
作为这些方法的参数显式传递。可以在启动时配置 SecurityContextHolder
以指定如何存储上下文。
SecurityContext
从 SecurityContextHolder
获取,包含当前通过身份认证(Authenticated)的用户的 Authentication
对象。
Authentication
Authentication
在 Spring Security 中有两个主要用途:
- 作为
AuthenticationManager
的输入提供用户提交的用于身份认证的凭据。在此场景下使用时isAuthenticated()
方法返回false
; - 代表当前已通过身份认证的用户,可以从
SecurityContext
中获取当前的Authentication
对象。
Authentication
对象 包含:
-
principal
:用于识别用户身份,如果使用用户名/密码方式执行的认证,这通常是一个UserDetails
实例。 -
credentials
:通常是密码,在很多情况下,一旦用户通过身份认证,这部分内容便会被清除以确保不会泄露。 -
authorities
:GrantedAuthority
集合,是用户被授予的更高级别权限,如角色和范围。
GrantedAuthority
GrantedAuthority
是用户被授予的更高级别权限,如角色和范围。
GrantedAuthority
集合可以通过 Authentication.getAuthorities()
获取。
AuthenticationManager
定义 Spring Security 过滤器如何执行身份认证的 API。认证通过后返回的 Authentication
对象由调用 AuthenticationManager
的控制器(Controller)设置到 SecurityContextHolder
中。
如果不使用 Spring Security 过滤器,可以直接设置 SecurityContextHolder
,并不需要使用 AuthenticationManager
。
ProviderManager
ProviderManager
是 AuthenticationManager
最常用的实现。ProviderManager
将认证委托给一个 AuthenticationProvider
列表,每个 AuthenticationProvider
都有机会指明认证结果是成功还是失败,又或无法做出认证结果决定并允许下游的 AuthenticationProvider
来做此决定。
如果所有已配置的 AuthenticationProvider
都无法做出认证结果决定,则认证结果即为失败并抛出一个 ProviderNotFoundException
异常。ProviderNotFoundException
异常继承自 AuthenticationException
,说明 ProviderManager
未配置支持此类型身份认证。
AuthenticationProvider
被 ProviderManager
用于执行特定类型的身份认证。ProviderManager
中可以注入多个 AuthenticationProvider
,每个 AuthenticationProvider
执行一种特定类型的身份认证,例如:
-
DaoAuthenticationProvider
:支持基于用户名/密码的基础认证; -
JwtAuthenticationProvider
:支持认证 JWT Token。
带有 AuthenticationEntryPoint 的请求凭证
AuthenticationEntryPoint
用于发送 HTTP 响应,此响应包含了请求客户端认证凭证。有时客户端在请求资源时会主动带上认证凭证,在这些情况下 Spring Security 是不需要发送 HTTP 响应要求客户端发送认证凭证,因为已经在之前的请求中带上了。但在另一些情况下,客户端在尚未认证时请求了一些未授权的资源,此时需要发送一个 AuthenticationEntryPoint
实现要求客户端发回认证凭证。
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter
是执行用户身份认证的最基础的过滤器。
AbstractAuthenticationProcessingFilter
执行认证的流程:
- 用户提交了认证凭证后,
AbstractAuthenticationProcessingFilter
从要认证的HttpServletRequest
中创建了一个Authentication
对象,创建的Authentication
对象的类型取决于AbstractAuthenticationProcessingFilter
的子类。例如,UsernamePasswordAuthenticationFilter
从HttpServletRequest
中解析出username
和password
,并据此创建UsernamePasswordAuthenticationToken
; -
Authentication
对象被传递给AuthenticationManager
进行身份认证; - 如果认证失败将执行以下操作:
-
SecurityContextHolder
被清空。 -
RememberMeServices.loginFail
被调用,如果未配置Remember Me
则不处理。 -
AuthenticationFailureHandler
被调用。
-
- 如果认证成功则执行以下操作:
- 通知
SessionAuthenticationStrategy
有一个新的登录。 -
Authentication
被设置到SecurityContextHolder
中,之后SecurityContextPersistenceFilter
将SecurityContext
保存到HttpSession
中。 -
RememberMeServices.loginSuccess
被调用,如果未配置Remember Me
则不处理 -
ApplicationEventPublisher
发布一个InteractiveAuthenticationSuccessEvent
事件。
- 通知
网友评论