【发布时间】:2019-05-30 13:12:12
【问题描述】:
在一个多模块应用程序中,我定义了 5 个映射到同一个 FilterChain 的 RequestMatchers,如下所示:
@Configuration
public class Module1SecurityFilterChain extends ResourceServerConfigurerAdapter {
@Override
public void configure( HttpSecurity http ) throws Exception {
http.sessionManagement().sessionCreationPolicy( STATELESS );
http.requestMatchers().antMatchers( "/module1/**")
.and()
.authorizeRequests()
.antMatchers( "/module1/resource").authenticated()
.antMatchers( "/module1/test" ).access( "#oauth2.isClient()")
.anyRequest().access( "#oauth2.hasScope('webclient')" );
}
}
模块2:
@Configuration
public class Module2SecurityFilterChain extends ResourceServerConfigurerAdapter {
@Override
public void configure( HttpSecurity http ) throws Exception {
http.sessionManagement().sessionCreationPolicy( STATELESS );
http.requestMatchers().antMatchers( "/module2/**")
.and()
.authorizeRequests()
.antMatchers( "/module2/resource").authenticated()
.antMatchers( "/module2/test" ).access( "#oauth2.isClient()")
.anyRequest().access( "#oauth2.hasScope('webclient')" );
}
}
并启用方法安全性:
@Configuration
@EnableGlobalMethodSecurity( prePostEnabled = true, securedEnabled = true )
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
问题是所有 #oauth2.xx 表达式仅针对第一个模块 requestmatcher /module1/** 进行评估,而在其他模块中被忽略。当我对用户进行身份验证并尝试访问/module1/test 时,访问被拒绝,而当访问/module2/test 时,访问被授予(也应该被拒绝)。
谁能解释一下为什么以及如何解决这个问题?我知道 Spring Security 一点也不简单…… 再次感谢。
编辑 @Darren Forsythe(感谢您的评论) 创建的过滤器链是:
INFO | o.s.s.w.DefaultSecurityFilterChain | Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@f55a810b, org.springframework.security.web.context.SecurityContextPersistenceFilter@85021903, org.springframework.security.web.header.HeaderWriterFilter@1d0744d1, org.springframework.security.web.authentication.logout.LogoutFilter@2d15146a, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@c38f3266, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@8f9bf85, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@74a71be5, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@e4eb6cc, org.springframework.security.web.session.SessionManagementFilter@22f6b39a, org.springframework.security.web.access.ExceptionTranslationFilter@960c464f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@f7a19dc5]
INFO | o.s.s.w.DefaultSecurityFilterChain | Creating filter chain: OrRequestMatcher [requestMatchers=[Ant [pattern='/module1/**'], Ant [pattern='/module2/**'], Ant [pattern='/module3/**'], Ant [pattern='/module4/**'], Ant [pattern='/module5/**'], Ant [pattern='/module6/**']]], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@38ef2427, org.springframework.security.web.context.SecurityContextPersistenceFilter@a26ff7af, org.springframework.security.web.header.HeaderWriterFilter@5344e710, org.springframework.security.web.authentication.logout.LogoutFilter@da0534c8, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@2956c7ab, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5682f610, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@f4cbf7a4, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@d1b1395a, org.springframework.security.web.session.SessionManagementFilter@d352f8ab, org.springframework.security.web.access.ExceptionTranslationFilter@9bb1d86, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@73c7a695]
INFO | o.s.s.w.DefaultSecurityFilterChain | Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1cc2056f, org.springframework.security.web.context.SecurityContextPersistenceFilter@259d95db, org.springframework.security.web.header.HeaderWriterFilter@de089e0b, org.springframework.security.web.authentication.logout.LogoutFilter@8b86b4c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@96304ca8, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1d5b7e4b, org.springframework.security.web.session.SessionManagementFilter@bd586b4d, org.springframework.security.web.access.ExceptionTranslationFilter@7cff2571]
如您所见,所有模块的 url 都通过以下过滤器列表映射到同一个过滤器链:
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
OAuth2AuthenticationProcessingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
我不明白的是,为什么对于其他模块,#oauth2.xx 表达式没有被评估,因为 FilterChain 是相同的?
【问题讨论】:
-
我不记得确切的答案,但我相信这是因为当您指定路径时,安全过滤器链将使用 Any 匹配器创建,所有请求都将放入第一条链。如果您在创建过滤器链时检查启动日志,您应该看到两个正在创建,两者都将是任何匹配器并包含单独的过滤器。您需要先在 http 安全中设置一个方法,以指定过滤器适用于哪些请求
-
@akuma8 为了更清楚:您在第二个配置中覆盖属性
.authorizeRequests()。 -
@akuma8 我发现了另一个包含解决方案的问题:stackoverflow.com/questions/47894809/…您可以将该问题用作重复目标。
-
@akuma8,它在这里:docs.spring.io/spring-security/site/docs/current/reference/…,它说匹配器是按声明顺序处理的。不过,这有点微妙。当发生这种情况时,我已经向 Spring Security 添加了一张快速失败的票:github.com/spring-projects/spring-security/issues/6359
标签: spring spring-boot spring-security spring-security-oauth2