SpringSecurity的架构
前言
由于自动翻译太过拉跨,所以我自己手动翻译了一些SpringSecurity框架文档,顺带提高自己的英语阅读水平。如果觉得翻译的不对,那么大家就多从自己身上找找毛病。
基本信息
版本:5.7.2
网址:https://docs.spring.io/spring-security/reference/servlet/architecture.html
笔记日期:2022-6-24
体系机构
这一部分我们讨论基于Servlet应用程序的SpringSecurity的高级架构。我们构建了这种高级的理解在Authentication, Authorization, Protection Against Exploits的引用中。
过滤器复习
这个客户端发出一个请求给应用程序, 并且容器创建了一个包含Filter(过滤器)和服务程序的过滤链,过滤器和服务程序应该基于请求的地址来处理这些请求。在SpringMVC的应用程序中servlet是一个DispatcherServlet的实例。一个servelet最多可以处理一个的请求和响应。然而,超过一个的Filter可以这样使用:
1、防止下方的过滤器或者Servlet被调用。在这种情况下,过滤器通常写入HttpServletResponse。
2、通过使用下方的过滤器和servlet改变请求或者响应。
以上的能力通过过滤链(FilterChain)被传递给过滤器(Filter)。
因为一个过滤器只影响下方过滤器和servlet, 所以每个过滤器被调用的顺序就显得极为重要。
DelegatingFilterProxy(委托过滤代理)
Spring 提供了一个名叫DelegatingFilterProxy的过滤器,它允许在servlet容器的生命周期和Spring应用程序上下文之间建立关系。虽然这个servlet容器允许使用他自己的标准去注册过滤器,但它并不会注意到Spring定义的Bean。虽然DelegatingFilterProxy可以 以标准的servlet容器机制注册,但它还是将所有的工作委托给一个实现了过滤器的Spring Bean。
这里有一张DelegatingFilterProxy如何融入到过滤器和过滤链里的图片。
DelegatingFilterProxy从ApplicationContext寻找 Filter0, 随后调用这个Bean。DelegatingFilterProxy的伪代码如下所示:
DelegatingFilterProxy的另一个好处是延迟加载Filter的Bean实例。这点很重要,因为容器需要在启动之前就要去注册过滤器实例。然而,Spring通常需要等到Filter实例被注册之后,才使用ContextLoaderListener去加载Spring的Beans。
FilterChainProxy(过滤链代理)
Spring Security的Servlet包含在FilterChainProxy中。FilterChainProxy是一个由SpringSecurity提供的一个特殊的Filter,它允许通过SecurityFilterChain委托给多个Filter。因为FilerChainProxy是一个Bean,所以它一般被包装在DelegatingFilterProxy中。
SecurityFilterChain(安全过滤链)
SecurityFilterChain是由FilterChainProxy用于确定哪些Spring Security Filter 应该被当前请求调用。
以上的Security Filter通常是Bean的形式存在于SecurityFilterChain中,但它们由FilterChainProxy注册,而不是DelegatingFilterProxy,这相较于直接向Servlet容器或DelegatingFilterProxy注册有很多的优势。
首先,它为Spring Security的所有Servlet支持提供了一个起点。因此,如果您试图对Spring Security的Servlet支持进行故障排除,在FilterChainProxy中添加断点是一个很好的(调试)起点。
其次,由于FilterChainProxy是SpringSecurity使用的核心,它可以执行不被视为可选的任务。例如,它可以清理SecurityConte以避免内存泄漏。它还应用了Spring Security的HttpFirewall来保护应用程序免受某些类型的攻击。
此外,它在确定一个应当被调用的SecurityFilterChain时更加灵活。在Servlet容器中,过滤器的调用仅基于URL。然而,FilterChainProxy通过利用RequestMatcher接口,可以基于HttpServletRequest中的任何内容确定调用。
事实上,FilterChainProxy可以用来确定应该使用哪个SecurityFilterChain。这允许为应用程序的不同部分提供完全独立的配置。
在多个SecurityFilterChain情况中FilterChainProxy决定应该使用哪一个SecurityFilterChain。只有第一个匹配的SecurityFilterChain才会被调用。如果请求的URL是**/api/messages/,它将首先会匹配上SecurityFilterChain0**,因此只会调用SecurityFilterChain0,即使SecurityFilterChainN(最后一个SecurityFilterChain)也会被匹配上。如果请求的URL是/messages/,它不会与SecurityFilterChain0的/api/messages/相匹配,所以FilterChainProxy将继续尝试其他所有的SecurityFilterChain。假设没有其他模式(0 – n中间),SecurityFilterChain 实例匹配的SecurityFilterChainN将被调用。
请注意,SecurityFilterChain0只配置了三个过滤器。但是,SecurityFilterChainN配置了四个过滤器。值得注意的是,每一个SecurityFilterChain都是唯一并且可以单独配置。事实上,一个SecurityFilterChain可能一个Filter也没有,如果应用程序希望Spring Security忽略某些请求的话。
Security Filters(安全过滤器)
Security Filter 被SecurityFilterChain的API插入到FilterChainProxy中。这些Filter的顺序是很重要的。通常我们并不需要去知道SpringSecurity中Filter的顺序。但有时候,知道顺序是有帮助的。
以下是SpringSecurity Filter的综合清单顺序(注释为自己找的资料猜着写的):
//强制要求创建Session过滤器 用于强制生成Session
//与下面的SessionManagementFilter相关联
ForceEagerSessionCreationFilter
//通道过滤器 规定哪些请求必须走http协议 哪些走https协议
ChannelProcessingFilter
//Web异步管理集成过滤器
//此过滤器使得WebAsync异步线程能够获取到当前认证信息
WebAsyncManagerIntegrationFilter
//安全上下文存在过滤器
//控制SecurityContext的在一次请求中的生命周期,请求结束时清空,防止内存泄漏。
SecurityContextPersistenceFilter
//请求头写入过滤器 用来给相应添加一些header
HeaderWriterFilter
//跨域过滤器 一般用在跨域请求资源的时候
CorsFilter
//跨域请求伪造过滤器 用于防止csrf攻击
CsrfFilter
//登出过滤器 退出登录时的逻辑
LogoutFilter
//Oauth2请求鉴权重定向过滤器,需配合OAuth2.0的模块使用
OAuth2AuthorizationRequestRedirectFilter
//Saml2单点认证过滤器。需配合Spring Security SAML模块使用。
Saml2WebSsoAuthenticationRequestFilter
//X.509证书认证过滤器。
X509AuthenticationFilter
//预认证处理的抽象过滤器 自定义过滤器的基类
AbstractPreAuthenticatedProcessingFilter
//CAS 单点登录认证过滤器 。配合Spring Security CAS模块使用
CasAuthenticationFilter
//OAuth2 登录认证过滤器。处理通过 OAuth2 进行认证登录的逻辑
OAuth2LoginAuthenticationFilter
//SMAL 的 SSO 单点登录认证过滤器
Saml2WebSsoAuthenticationFilter
//用户名密码认证过滤器。 最主要的认证过滤器 账户的验证在这里进行
UsernamePasswordAuthenticationFilter
//OpenID认证过滤器。需要在依赖中依赖额外的相关模块才能启用它
OpenIDAuthenticationFilter
//默认登入页生成过滤器。默认 /login
DefaultLoginPageGeneratingFilter
//默认登出页生成过滤器。 默认 /logout
DefaultLogoutPageGeneratingFilter
//session管理,用于判断session是否过期。该过滤器可能会被多次执行
ConcurrentSessionFilter
//摘要认证过滤器。Web 应用程序中流行的可选的身份验证机制
DigestAuthenticationFilter
//Bearer标准token认证过滤器。
BearerTokenAuthenticationFilter
//标准认证过滤器 Web 应用程序中流行的可选的身份验证机制
//负责处理 HTTP 头中显示的基本身份验证凭据
BasicAuthenticationFilter
//请求缓存过滤器。主要作用是认证完成后恢复认证前的请求继续执行
RequestCacheAwareFilter
//安全上下文持有者感知请求过滤器 用于实现servlet的一些api
SecurityContextHolderAwareRequestFilter
//Jaas认证过滤器。适用于JAAS (Java 认证授权服务)
JaasApiIntegrationFilter
//记住我认证过滤器。处理“记住我”功能的过滤器。
RememberMeAuthenticationFilter
//匿名认证过滤器 如果访问不需要授权的资源 则以匿名身份访问
AnonymousAuthenticationFilter
//OAuth2授权码过滤器
OAuth2AuthorizationCodeGrantFilter
//Session管理器过滤
//其中SessionAuthenticationStrategy 用于管理 Session
SessionManagementFilter
//异常翻译过滤器 过滤链中的异常会等到了此处再一并处理
ExceptionTranslationFilter
//过滤器安全拦截器 这个过滤器决定了访问特定路径应该具备的权限
FilterSecurityInterceptor
//账户切换过滤器 用来做账户切换的
SwitchUserFilter
Handling Security Exceptions(处理Security异常)
ExceptionTranslationFilter允许将AccessDeniedException和AuthenticationException转换为HTTP响应。 ExceptionTranslationFilter作为SecurityFilter之一插入到FilterChainProxy中。
1、首先ExceptionTranslationFilter去调用**FilterChain.doFilter(request, response)**方法调用应用程序的其他部分。
2、如果一个用户并未认证或者是一个认证异常(AuthenticationException),(未认证的话)然后就Start Authentication:
一、清除SecurityContextHolder
二、将HttpServletRequest保存在RequestCache中。当用户成功通过认证,这个RequestCache用于重现最初的request。
三、AuthenticationEntryPoint被用作是客户端请求的证书。例如,它可能重定向到登录页面或发送WWW-Authenticate标头。
3、如果是AccessDeniedException(拒绝访问异常),就会拒绝访问。调用AccessDeniedHandler来处理被拒绝的访问。
注意:如果一个应用程序没有抛出任何异常:AccessDeniedException或者AuthenticationException,那么AccessDeniedHandler不会做任何事情。
ExceptionTranslationFilter的伪代码看起来像以下这样:
1、回顾上面的过滤器复习,您会记得调用FilterChain.doFilter(request,response)相当于调用应用程序的其余部分。这意味着如果程序的其他部分(即FilterSecurityInterceptor or method security)抛出一个AuthenticationException或者AccessDeniedException 就会在这里被捕获和处理。
2、如果用户未被认证或者是一个AuthenticationException,就会Start Authentication(开始认证)。
3、否者,拒绝访问