一 基本原理
Spring Security的Servlet支持基于Servlet过滤器,因此通常首先了解过滤器的作用会很有帮助。 下图显示了单个HTTP请求的处理程序的典型分层。
Spring提供了一个名为DelegatingFilterProxy
的Filter实现,可以在Servlet容器的生命周期和Spring的ApplicationContext
之间进行桥接。 Servlet容器允许使用其自己的标准注册Filters,但是它不知道Spring定义的Bean。 DelegatingFilterProxy
可以通过标准的Servlet容器机制进行注册,但是可以将所有工作委托给实现Filter的Spring Bean。
这是DelegatingFilterProxy
如何适合Filters和FilterChain的图片。
DelegatingFilterProxy从ApplicationContext中查找Bean Filter0,然后调用Bean Filter0。下面可以看到DelegatingFilterProxy的伪代码。
1 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) { |
DelegatingFilterProxy的另一个好处是它允许延迟查找filterbean实例。这一点很重要,因为容器需要在容器启动之前注册过滤器实例。但是,Spring通常使用ContextLoaderListener来加载springbean,直到需要注册过滤器实例之后才会加载。
springsecurity的Servlet支持包含在FilterChainProxy中。FilterChainProxy是springsecurity提供的一种特殊的过滤器,它允许通过SecurityFilterChain委托给许多过滤器实例。因为FilterChainProxy是一个Bean,它通常被包装在DelegatingFilterProxy中。
FilterChainProxy使用SecurityFilterChain来确定应该为此请求调用哪些Spring安全过滤器。
SecurityFilterChain中的安全过滤器通常是bean,但是它们注册到FilterChainProxy而不是DelegatingFilterProxy。FilterChainProxy为直接注册Servlet容器或DelegatingFilterProxy提供了许多优点。首先,它为springsecurity的所有Servlet支持提供了一个起点。出于这个原因,如果您试图对springsecurity的Servlet支持进行故障排除,那么在FilterChainProxy中添加一个调试点是一个很好的起点。
其次,由于FilterChainProxy是Spring安全使用的核心,它可以执行不被视为可选的任务。例如,它清除SecurityContext以避免内存泄漏。它还应用springsecurity的HttpFirewall来保护应用程序免受某些类型的攻击。
此外,它在确定何时应该调用SecurityFilterChain时提供了更大的灵活性。在Servlet容器中,仅根据URL调用过滤器。但是,FilterChainProxy可以利用RequestMatcher接口根据HttpServletRequest中的任何内容来确定调用。
事实上,FilterChainProxy可以用来确定应该使用哪个SecurityFilterChain。这允许为应用程序的不同切片提供完全独立的配置。
二 过滤器的顺序
安全筛选器通过SecurityFilterChain API插入到FilterChainProxy中。 过滤器的顺序很重要。 通常不必知道Spring Security的过滤器的顺序。 但是,有时候了解顺序是有益的
以下是Spring Security过滤器顺序的完整列表:
- ChannelProcessingFilter
- ConcurrentSessionFilter
- WebAsyncManagerIntegrationFilter
- SecurityContextPersistenceFilter
- HeaderWriterFilter
- CorsFilter
- CsrfFilter
- LogoutFilter
- OAuth2AuthorizationRequestRedirectFilter
- Saml2WebSsoAuthenticationRequestFilter
- X509AuthenticationFilter
- AbstractPreAuthenticatedProcessingFilter
- CasAuthenticationFilter
- OAuth2LoginAuthenticationFilter
- Saml2WebSsoAuthenticationFilter
UsernamePasswordAuthenticationFilter
- ConcurrentSessionFilter
- OpenIDAuthenticationFilter
- DefaultLoginPageGeneratingFilter
- DefaultLogoutPageGeneratingFilter
DigestAuthenticationFilter
- BearerTokenAuthenticationFilter
BasicAuthenticationFilter
- RequestCacheAwareFilter
- SecurityContextHolderAwareRequestFilter
- JaasApiIntegrationFilter
- RememberMeAuthenticationFilter
- AnonymousAuthenticationFilter
- OAuth2AuthorizationCodeGrantFilter
- SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
- SwitchUserFilter
三 应用授权的工作原理
FilterSecurityInterceptor为HttpServletRequests提供授权。它作为安全过滤器之一插入FilterChainProxy。
- FilterSecurityInterceptor从SecurityContextHolder获得身份验证。
- FilterSecurityInterceptor从传递到FilterSecurityInterceptor的HttpServletRequest、HttpServletResponse和FilterChain创建FilterInvocation。
- 将FilterInvocation传递给SecurityMetadataSource以获取ConfigAttributes。
- 将身份验证、FilterInvocation和ConfigAttributes传递给AccessDecisionManager。
- 如果授权被拒绝,则抛出AccessDeniedException。在本例中,ExceptionTranslationFilter处理AccessDeniedException。
- 如果访问被授予,FilterSecurityInterceptor将继续使用FilterChain,它允许应用程序正常处理。
默认情况下,Spring安全性的授权将要求对所有请求进行身份验证。显式配置如下:
1 | protected void configure(HttpSecurity http) throws Exception { |
我们可以通过按优先级添加更多规则来配置spring security,使其具有不同的规则。
1 | protected void configure(HttpSecurity http) throws Exception { |
- 这里指定了多个授权规则。每一条规则都是按照它们被声明的顺序来考虑的。我们指定了多个任何用户都可以访问的URL模式。特别是,如果URL以“/resources/”开头、或等于“/signup”或等于“/about”开头,则任何用户都可以访问请求。
- 任何以“/admin/”开头的URL将被限制为具有“role\u admin”角色的用户。您会注意到,由于我们调用的是hasRole方法,所以不需要指定“ROLE_”前缀。
- 任何以“/db/”开头的URL都要求用户同时具有“ROLEADMIN”和“ROLE_DBA”。您会注意到,由于我们使用的是hasRole表达式,所以不需要指定“ROLE”前缀。
- 任何尚未在上匹配的URL都将被拒绝访问。如果您不想意外忘记更新授权规则,这是一个很好的策略。