禁用执行器健康端点的 webflux(反应式)安全性

Posted

技术标签:

【中文标题】禁用执行器健康端点的 webflux(反应式)安全性【英文标题】:Disable webflux (reactive) security for actuator health endpoint 【发布时间】:2019-12-28 01:37:02 【问题描述】:

我有一个包含 WebFlux、Health actuator 和 Spring security 的项目。我正在尝试构建自定义身份验证,但该身份验证也适用于健康执行器端点。如何禁用它?

根据文档,我实现了一个自定义 ServerSecurityContextRepository,这是它看起来有点像的基本版本:

@Component
class MySecurityContextRepository: ServerSecurityContextRepository 
    override fun save(exchange: ServerWebExchange?, context: SecurityContext?) = Mono.empty()

    override fun load(exchange: ServerWebExchange) = Mono.error(ResponseStatusException(HttpStatus.UNAUTHORIZED, "Access denied"))

根据文档,我不应该被要求做任何额外的配置来禁用健康端点上的身份验证。这是来自application.yml的配置:

management:
  metrics:
        web:
          server:
            auto-time-requests: true
            requests-metric-name: xxx-xxx-xxx
        export:
          statsd:
            enabled: xxxx
            host: xxxxxxxxxxxx
            flavor: xxx
  endpoint:
      health:
        enabled: true
  endpoints:
      web:
          base-path: /application

这不起作用,因为我从 /application/health 端点看到了 401。所以我也将它添加到我的安全配置中:

@EnableWebFluxSecurity
class SecurityConfig @Autowired constructor(
        private val myRepository: MySecurityContextRepository
) 
    @Bean
    fun securityWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain 
        http.securityContextRepository(myRepository)
        http.authorizeExchange()
                .pathMatchers("/application/health").permitAll()
                .anyExchange().permitAll()

        http.cors().disable()
        http.csrf().disable()
        http.formLogin().disable()

        return http.build()
    

尽管添加此操作 curl http://localhost:8080/application/health/ 会导致 "name":"xxxxxx","message":"Unknown Error","response":"401 UNAUTHORIZED \"Access denied\"" 并且状态代码也是 401。如何禁用对我的健康端点的授权?

【问题讨论】:

【参考方案1】:

所以在没有帮助之后,我开始查看源代码,结果发现ServerSecurityContextRepository 总是为HealthEndpointInfoEndpoint 调用,所以我自己添加了跳过存储库中的身份验证检查的逻辑。您可以轻松做到:

val HEALTH_ENDPOINTS = EndpointRequest.to(HealthEndpoint::class.java, InfoEndpoint::class.java)

现在您可以执行以下操作:

            return HEALTH_ENDPOINTS.matches(exchange).flatMap  matches ->
                if (matches.isMatch) 
                    Mono.just(SecurityContextImpl(GuestAuthToken))
                 else 
                    Mono.empty()
                
            

这样我就不会在我的存储库中硬编码任何路径。这并不理想,但可以完成工作。

【讨论】:

【参考方案2】:

最好使用EndpointRequest 来匹配执行器端点,因为它会匹配您的配置。使用反应式导入(不是 servlet)。

application.yml:

management:
  endpoint:
      health:
        enabled: true
  endpoints:
    web:
      base-path: /application

WebSecurityConfig.java:

@Configuration
@EnableWebFluxSecurity
public class WebSecurityConfig 
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 
        return http.csrf().disable()
                .authorizeExchange()
                .matchers(EndpointRequest.to("health")).permitAll()
                .and().build();
    

【讨论】:

【参考方案3】:

关于 spring docu 29.2 WebFlux Security 你只需要添加:

import org.springframework.boot.autoconfigure.security.reactive.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

@Configuration
public class WebFluxSecurityConfigurer 

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) 
        return http
                .authorizeExchange()
                .pathMatchers("/status/**")
                .permitAll().and()
                .build();
    

不要忘记添加所有可能的路径,例如 ../health 和 ../health/ 或者使用通配符更好

【讨论】:

以上是关于禁用执行器健康端点的 webflux(反应式)安全性的主要内容,如果未能解决你的问题,请参考以下文章

Webflux,使用Websocket如何防止订阅两次反应式redis消息操作

Spring Boot:为执行器端点禁用 https

禁用传输编码:在 Spring Webflux 响应中分块

Spring Webflux 2.4.2 - 执行器 /auditevents /httptrace /integrationgraph /sessions 端点上的 404

如何使用spring webflux在功能性反应java中编写具有多个if else的复杂代码

Spring Webflux + LDAP/Kerberos 安全性