我是通过松哥的博客学习SpringSecurity的,地址是http://itboyhub.com/2021/01/26/spring-security-guide/。对SpringSecurity的使用有了初步的认识。并根据松哥的博客跟了源码,但是每个人的思路不一样,看完之后还有点模糊。对其中的一些用法不够深刻。想了下还是根据自己的思路记录下SpringSecurity。
体系结构
SpringSecurity是通过Filter来实现一系列功能的。Filter的流程如下:
客户端向应用程序发送一个请求,容器创建一个FilterChain,其中包含过滤器和Servlet,它们应该根据请求URI的路径处理HttpServlet请求。在Spring MVC应用程序中,Servlet是DispatcherServlet的一个实例。最多一个Servlet可以处理单个HttpServlet请求和HttpServlet响应。
DelegatingFilterProxy
Spring提供了一个名为DelegatingFilterProxy的Filter实现,它允许Servlet容器的生命周期和Spring的ApplicationContext之间进行桥接。Servlet容器允许使用自己的标准注册Filter,但它不知道Spring定义的Beans。DelegatingFilterProxy可以通过标准Servlet容器机制注册,但将所有工作委托给实现Filter的Spring Bean。
DelegatingFilterProxy从ApplicationContext中查找Bean Filter0,然后调用Bean Filter0。
DelegatingFilterProxy的另一个好处是,它允许延迟查找Filter bean实例。这一点很重要,因为容器需要在启动容器之前注册Filter实例。然而,Spring通常使用ContextLoaderListener来加载Spring Beans,这要等到需要注册Filter实例之后才能完成。
FilterChainProxy
SpringSecurity的Servlet支持包含在FilterChainProxy中。FilterChainProxy是Spring Security提供的一种特殊Filter,允许通过SecurityFilterChain将其委托给许多Filter实例。由于FilterChainProxy是一个Bean,它通常封装在DelegatingFilterProxy中。
SecurityFilterChain
FilterChainProxy使用SecurityFilterChain来确定应为此请求调用哪些Spring Security Filter。
SecurityFilterChain中的安全过滤器通常是Beans,但它们是用FilterChainProxy而不是DelegatingFilterProxy注册的。FilterChainProxy为直接向Servlet容器或DelegatingFilterProxy注册提供了许多优势。首先,它为SpringSecurity的Servlet支持提供了一个起点。
其次,由于FilterChainProxy是Spring Security使用的核心,它可以执行不被视为可选的任务。例如,它清除SecurityContext以避免内存泄漏。它还应用了Spring Security的HttpFirewall来保护应用程序免受某些类型的攻击。
此外,它在确定何时应该调用SecurityFilterChain时提供了更大的灵活性。在Servlet容器中,过滤器仅根据URL调用。然而,FilterChainProxy可以通过利用RequestMatcher接口,根据HttpServlet请求中的任何内容来确定调用。
事实上,FilterChainProxy可以用来确定应该使用哪个SecurityFilterChain。这允许为应用程序的不同部分提供完全独立的配置。
在多重安全过滤器链中,图FilterChainProxy决定应使用哪个安全过滤器链。只有匹配的第一个SecurityFilterChain才会被调用。如果请求/api/messages/的URL,它将首先在SecurityFilterChain0的/api/**
模式上匹配,因此只有SecurityFilterChain 0会被调用,即使它在SecurityFilterChainn上也匹配。如果请求了/messages/的URL,那么它将与SecurityFilterChain0的/api/**
模式不匹配,因此FilterChainProxy将继续尝试每个SecurityFilterChain。假设没有其他与SecurityFilterChainn匹配的SecurityFilterChain实例将被调用。
请注意,SecurityFilterChain0只配置了三个安全筛选器实例。但是,SecurityFilterChainn配置了四个安全筛选器。需要注意的是,每个SecurityFilterChain都可以是唯一的,并且可以单独配置。事实上,如果应用程序希望Spring security忽略某些请求,那么SecurityFilterChain可能没有安全过滤器。
Spring Security Filter
安全过滤器通过SecurityFilterChain API插入到FilterChainProxy中。过滤器的顺序很重要。
Spring Security Filter如下:
ForceEagerSessionCreationFilter
ChannelProcessingFilter
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CorsFilter
CsrfFilter
LogoutFilter
OAuth2AuthorizationRequestRedirectFilter
Saml2WebSsoAuthenticationRequestFilter
X509AuthenticationFilter
AbstractPreAuthenticatedProcessingFilter
CasAuthenticationFilter
OAuth2LoginAuthenticationFilter
Saml2WebSsoAuthenticationFilter
UsernamePasswordAuthenticationFilter
OpenIDAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
ConcurrentSessionFilter
DigestAuthenticationFilter
BearerTokenAuthenticationFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
JaasApiIntegrationFilter
RememberMeAuthenticationFilter
AnonymousAuthenticationFilter
OAuth2AuthorizationCodeGrantFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
SwitchUserFilter
处理Security异常
ExceptionTranslationFilter允许将AccessDeniedException和AuthenticationException转换为HTTP响应。
ExceptionTranslationFilter作为安全筛选器之一插入到FilterChainProxy中。
1、首先,ExceptionTranslationFilter调用FilterChain.doFilter(请求,响应)来调用应用程序的其余部分。
2、如果用户未通过身份验证或是AuthenticationException,则启动身份验证。将会
a、清除 SecurityContextHolder,
b、保存HttpServlet请求,以便在身份验证成功后可以使用它来重播原始请求。
c、AuthenticationEntryPoint用于向客户端请求凭据。例如,它可能重定向到登录页面或发送WWW-Authenticate标头。
3、否则,如果是AccessDeniedException,则为Access Denied。调用AccessDeniedHandler来处理被拒绝的访问
在身份验证之间保存请求
如“处理安全异常”中所示,当请求没有身份验证并且是针对需要身份验证的资源时,需要保存针对已验证资源的请求,以便在身份验证成功后重新请求。在Spring Security中,这是通过使用RequestCache实现保存HttpServlet请求来完成的。
HttpServlet请求保存在RequestCache中。当用户成功进行身份验证时,RequestCache将用于重播原始请求。RequestCacheAwareFilter使用RequestCache来保存HttpServlet请求。默认情况下,会使用HttpSessionRequestCache