在多模块应用中,我定义了5个映射到同一FilterChain的RequestMatchers,如下所示:
@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')" );
}
}
和模块2:
@Configuration
@EnableGlobalMethodSecurity( prePostEnabled = true, securedEnabled = true )
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
并启用了方法安全性:
#oauth2.xx
问题在于,所有/module1/**
表达式仅针对第一个模块requestmatcher /module1/test
求值,而在其他表达式中被忽略。当我对用户进行身份验证并尝试访问/module2/test
时,访问将按预期被拒绝,而当访问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]
时,访问被授予(也应被拒绝)。
有人可以解释我为什么以及如何解决这个问题吗?我知道Spring Security并不容易... 再次感谢。
编辑 @Darren Forsythe(感谢您的评论) 创建的过滤器链为:
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
OAuth2AuthenticationProcessingFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
如您所见,使用以下过滤器列表,所有模块的URL都映射到同一过滤器链:
#oauth2.xx
我不明白为什么对于其他模块,{{1}}表达式由于FilterChain相同而未求值?
答案 0 :(得分:0)
请求匹配器(在antMatchers
,anyRequest
等中指定)按指定的顺序由过滤器链处理。因为多个ResourceServiceConfiguredAdapter
实例只是配置了HttpSecurity
的同一实例,所以将为您的每个请求按如下方式处理匹配器:
if (uri == "/module1/resource") {
// ...
} else if (uri == "/module1/test") {
// ...
} else if (true) { // anyRequest
// ...
} else if (uri = "/module2/resource") {
// ...
} else if (uri = "/module2/test") {
// ...
}
如您所见,最后两个if条件永远不会满足。
您可以考虑以下两点:
anyRequest()
anyRequest
通常非常方便;但是,在这种情况下,由于试图将范围缩小到某些模块路径,因此您实际上并不是“任何请求”。您可以改为:
http
.requestMatchers()
.antMatchers("/module2/**")
.and()
.authorizeRequests()
.antMatchers("/module2/resource").authenticated()
.antMatchers("/module2/test").access( "#oauth2.isClient()")
.antMatchers("/module2/**").access( "#oauth2.hasScope('webclient')" );
这样,该模块就不会过度尝试尝试指定可能不知道的行为。
说实话,调用anyRequest
通常是无害的,因为您已经使用requestMatchers
缩小了过滤器链的范围。但是,由于您是用多个适配器组成一个HttpSecurity
,所以存在这种隐藏的复杂性。
oauth2ResourceServer()
-Spring Security 5.1 + 如果您使用的是Spring Security 5.1,那么实际上WebSecurityConfigurerAdapter
本身就内置了支持,因此您不再需要使用ResourceServerConfigurerAdapter
了,至少对于以下位置的JWT编码令牌而言:这点。这也很好,因为两个WebSecurityConfigurerAdapter
被视为单独的过滤器链。
根据所需的OAuth 2.0功能,您可以改为执行此操作:
@EnableWebSecurity
public class Module1Config extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/module1/**")
.and()
.authorizeRequests()
.antMatchers("/module1/resource").authenticated()
.anyRequest.hasRole("SCOPE_webclient")
.oauth2ResourceServer()
.jwt();
}
}
这是Spring Security的一个活跃的开发领域-将功能移植到WebSecurityConfigurerAdapter
中;因此,请务必与您的特定用例联系,以确保在尚未使用的情况下对其进行优先级排序。