如何配置两个安全过滤器链,以便在未经授权的情况下,只有一个使用 oath2Login 进行重定向,另一个返回 403

问题描述 投票:0回答:1

我有一个 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 上重定向,如果不复制大量最终类并修改它们,这是非常困难的。

spring-boot spring-security spring-cloud-gateway
1个回答
0
投票

所以我发现我需要做什么来配置两个安全链,一个 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)
© www.soinside.com 2019 - 2024. All rights reserved.