自定义 Spring Security 内部 WebClient

Posted

技术标签:

【中文标题】自定义 Spring Security 内部 WebClient【英文标题】:Customize Spring Security Internal WebClient 【发布时间】:2021-08-22 18:27:49 【问题描述】:

在咖啡馆热点 Wifi 中工作时,我注意到 Spring Security 在解析 application.yml 中设置的 JWK URI 时失败:

# application.yml
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          jwk-set-uri: https://some.vendor.com/.well-known/jwks.json

我注意到我拥有的另一段使用 org.springframework.web.reactive.function.client.WebClient 的代码有类似的行为,我可以通过更改地址解析器来解决此问题,如下所示:

val jvmBlockingResolver = HttpClient.create().resolver(DefaultAddressResolverGroup.INSTANCE)
val webClient = WebClient
            .builder()
            .clientConnector(ReactorClientHttpConnector(jvmBlockingResolver))
            .build()

深入 Spring Security 代码,我发现以下几行:

// NimbusReactiveJwtDecoder.java
package org.springframework.security.oauth2.jwt;

/* ... */

import org.springframework.web.reactive.function.client.WebClient;

/* ... */

// line 383:
source.setWebClient(this.webClient);

现在我坚信这个错误是因为这个WebClient。有没有办法解决这个问题?

我想我可以注入我的WebClient bean,但是现在我已经看到了代码,我认为这不会起作用。我找错地方了吗?这是 Spring Security 限制还是错误?

【问题讨论】:

为什么不尝试使用 builder docs.spring.io/spring-security/site/docs/current/api/org/… 并设置 webclient 并构建并将其作为 bean 返回到框架。 @Toerktumlare 感谢您的建议。它给了我一丝希望,但我仍然被困住了。构建器允许您更改 WebClient,它在内部使用 Reactor 的 HttpClient。我对这个组件如何在内部工作有了更多的了解。如果我证明不可能,我会尝试向 Spring Security 团队提出功能请求。 @Toerktumlare 我又试了一次,它成功了:) 桥是ReactorClientHttpConnector。有没有办法将您的评论推广到答案? 【参考方案1】:

感谢@Toerktumlare 的评论,我能够使用他的建议来创建自定义 bean:

@Bean
fun reactiveJwtDecoder(): ReactiveJwtDecoder 
    val jvmBlockingResolver = HttpClient.create().resolver(DefaultAddressResolverGroup.INSTANCE)
    val connector = ReactorClientHttpConnector(jvmBlockingResolver)
    val webClient = WebClient.builder().clientConnector(connector).build()
    return NimbusReactiveJwtDecoder.withJwkSetUri("https://example.com/.well-known/jwks.json")
        .webClient(webClient)
        .build()

也可以使用SecurityWebFilterChain builder 来做到这一点:

.oauth2ResourceServer 
    val jvmBlockingResolver = HttpClient.create().resolver(DefaultAddressResolverGroup.INSTANCE)
    val connector = ReactorClientHttpConnector(jvmBlockingResolver)
    val webClient = WebClient.builder().clientConnector(connector).build()
    it.jwt().jwtDecoder(
        NimbusReactiveJwtDecoder
            .withJwkSetUri("https://example.com/.well-known/jwks.json")
            .webClient(webClient)
            .build()
    )


【讨论】:

以上是关于自定义 Spring Security 内部 WebClient的主要内容,如果未能解决你的问题,请参考以下文章

spring boot整合 spring security之自定义认证

五 spring security 其他权限检验及自定义校验方法

spring security自定义指南

Spring Security入门(3-6)Spring Security 的鉴权 - 自定义权限前缀

使用 Spring Security 定义 HTTP 路由以仅服务“内部”请求

Spring Security 之自定义UserDetails