我有一个 Spring Cloud Gateway (gateway-mvc 4.5),我希望将任何 /ui 访问重定向到 oath2 登录身份验证服务器,并且如果会话中没有有效身份验证,则任何 api 调用都会失败。 /ui 可以工作,但 /api 总是失败并返回 403。
我的配置是...
@Bean
@Order(1)
SecurityFilterChain securityFilterChain_UI(final HttpSecurity httpSecurity,
final ClientRegistrationRepository clientRegistrationRepository) throws Exception {
// This security filter chain if for the UI which will redirect to the oath2 login if not authorised.
var ret = httpSecurity
.authorizeHttpRequests(exchanges -> exchanges
.requestMatchers("/ui/**").authenticated())
.oauth2Login(oAuth2LoginSpec -> oAuth2LoginSpec
.failureHandler(authenticationFailureHandler()))
.logout(logoutSpec -> logoutSpec
.logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_URL, "GET"))
.logoutSuccessHandler(logoutSuccessHandler(clientRegistrationRepository)))
.cors(cors -> cors
.configurationSource(corsConfigurationSource()))
.csrf(AbstractHttpConfigurer::disable)
.build();
return ret;
}
还有
@Bean
@Order(2)
SecurityFilterChain securityFilterChain_API(final HttpSecurity httpSecurity,
final ClientRegistrationRepository clientRegistrationRepository) throws Exception {
// This security filter chain if for the APIs which will fail if not authorised.
return httpSecurity
.authorizeHttpRequests(exchanges -> exchanges
.requestMatchers("/actuator/**").permitAll() // Don't authenticate the actuator
.requestMatchers("/api/**").authenticated())
.build();
}
这是正确的做法吗?
当我调试时,我看到 /api 只调用了 /ui 过滤器链(查看 RequestMatcherDelegatingAuthorizationManager 中的映射),这表明 securityFilterChain_API 不起作用。
如果我要使用一个安全过滤器链来执行此操作,我将必须重写 OAuth2AuthorizationRequestRedirectFilter 以不在 /api 上重定向,如果不复制大量最终类并修改它们,这是非常困难的。
所以我发现我需要做什么来配置两个安全链,一个 UI 链在需要时重定向到 oath2 登录,另一个 REST api 链在身份验证过期时失败。
@Bean
@Order(1)
SecurityFilterChain securityFilterChain_UI(final HttpSecurity httpSecurity,
final ClientRegistrationRepository clientRegistrationRepository) throws Exception {
// This security filter chain is for the UI which will redirect to the oath2 login if not authenticated.
return httpSecurity
.securityMatcher("/ui/**", "/oauth2/**", "/login/**", "/logout/**")
.authorizeHttpRequests(exchanges -> exchanges
.requestMatchers("/ui/**").authenticated())
.oauth2Login(withDefaults()) // Redirect to the oath2 login if not authorised.
.cors(withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.build();
}
@Bean
@Order(2)
SecurityFilterChain securityFilterChain_API(final HttpSecurity httpSecurity) throws Exception {
// This security filter chain is for the APIs which will fail if not authorised and actuator which is not
return httpSecurity
.securityMatcher("/api/**", "/actuator/**")
.authorizeHttpRequests(exchanges -> exchanges
.requestMatchers("/api/**").authenticated()
.requestMatchers("/actuator/**").permitAll()) // Don't authenticate the actuator.
.oauth2Client(withDefaults()) // Ensure authenticated with token.
.cors(AbstractHttpConfigurer::disable)
.logout(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable)
.build();
}
关键是使用 securityMatcher 将安全过滤器链限制为 oath2Login 的路径、UI 路径以及 REST api 的 oath2Client 路径。 并且还允许 oath2、登录和注销路径 ack 到 UI 安全过滤器链上。
通过 TRACE 登录,您可以看到 UI 链启用了以下过滤器...
Trying to match request against DefaultSecurityFilterChain
[RequestMatcher=Or [Mvc [pattern='/ui/**'], Mvc [pattern='/oauth/**'], Mvc [pattern='/oauth2/**'], Mvc [pattern='/logout/**'], Mvc [pattern='/login/**']], Filters=[
org.springframework.security.web.session.DisableEncodeUrlFilter@748101e8,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3cf3da1a,
org.springframework.security.web.context.SecurityContextHolderFilter@3e285e0c,
org.springframework.security.web.header.HeaderWriterFilter@7a410a0d,
org.springframework.web.filter.CorsFilter@fe88dcc,
org.springframework.security.web.authentication.logout.LogoutFilter@2ce526ae,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@628d6d8f,
org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter@c44a64e,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@6202b9a7,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@276c6e69,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6a040463,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@5b25f8b2,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5b1eb52d,
org.springframework.security.web.access.ExceptionTranslationFilter@5d4f0c7d,
org.springframework.security.web.access.intercept.AuthorizationFilter@4a4a669d]] (1/2)
还有 API 链...
Trying to match request against DefaultSecurityFilterChain
[RequestMatcher=Or [Mvc [pattern='/api/**'], Mvc [pattern='/actuator/**']], Filters=[
org.springframework.security.web.session.DisableEncodeUrlFilter@4f5ccf1c,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@49802c40,
org.springframework.security.web.context.SecurityContextHolderFilter@4d085b84,
org.springframework.security.web.header.HeaderWriterFilter@4584b0d4,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@12fcbb79,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@51e2481d,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@25e7d7e9,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@5dcca676,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter@453ba9ce,
org.springframework.security.web.access.ExceptionTranslationFilter@7050842c,
org.springframework.security.web.access.intercept.AuthorizationFilter@4a5e76ce]
] (2/2)