3

我在 Spring Boot Webflux 应用程序中使用 Spring 安全性主要在HTTPS端口上提供流量。但是,作为一项操作要求,我需要在我的 Spring Boot 应用程序中支持几个非安全的 REST API 路径,以进行健康检查等也需要公开HTTP

SecurityWebFilterChain那么,除了使用bean的已知路径之外,如何强制对 HTTPS 的所有请求?

这就是我定义我的SecurityWebFilterChainbean的方式:

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {    
    @Bean
    SecurityWebFilterChain webFilterChain( ServerHttpSecurity http )
     throws Exception {
         return http 
            .authorizeExchange(exchanges -> exchanges
                    .anyExchange().permitAll()
                    .and()
                    .exceptionHandling()
                    .authenticationEntryPoint((exchange, exception) ->
                        Mono.error(exception))
                    )
            .csrf().disable()
            .headers().disable()
            .logout().disable()
            .build();
    }
}

这显然不会按预期工作,因为它允许所有请求使用HTTPHTTPS方案,而我希望始终强制执行HTTPS,但路径除外,例如/health.

请建议我需要在上面的代码中进行哪些更改才能完成此操作。

4

2 回答 2

3

这是我想出解决这个问题的方法。我在.matchers( customMatcher )方法中调用自定义匹配器

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    private static final Set<String> UNSECURED = new HashSet<>( 
             Arrays.asList ( new String[] { "/health", "/heartbeat" } ) );

    @Bean
    SecurityWebFilterChain webFilterChain( final ServerHttpSecurity http ) {    
        return http
                .authorizeExchange(
                        exchanges -> exchanges
                        .matchers( this::blockUnsecured ).permitAll()
                        .and()
                        .exceptionHandling()
                        .authenticationEntryPoint(
                               (exchange, exception) -> Mono.error(exception))
                        )
                .csrf().disable()
                .headers().disable()
                .logout().disable()
                .httpBasic().disable()
                .build();
    }

    Mono<MatchResult> blockUnsecured( final ServerWebExchange exchange ) {    
        // Deny all requests except few known ones using "http" scheme
        URI uri = exchange.getRequest().getURI();

        boolean invalid = "http".equalsIgnoreCase( uri.getScheme() ) &&
                !UNSECURED.contains ( uri.getPath().toLowerCase() );    
        return invalid ? MatchResult.notMatch() : MatchResult.match();    
    }
}

不确定是否有更好的方法来做同样的事情。

于 2020-07-17T14:07:49.010 回答
0

通过复制创建自定义过滤器HttpsRedirectWebFilter,并且在该过滤器中,如果请求的 url 不是/health,您将对其进行修改,使其发送 401 而不是重定向

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {    
    @Bean
    SecurityWebFilterChain springWebFilterChain( ServerHttpSecurity http )
     throws Exception {
         return http.addFilterAt(your-custom-https-filter, 
                                 SecurityWebFiltersOrder.HTTPS_REDIRECT)
                    .
                  ......
    }

    
于 2020-07-16T14:07:12.093 回答