Spring Security (OAuth):如何在未公开 restTemplate 时添加请求标头?

Posted

技术标签:

【中文标题】Spring Security (OAuth):如何在未公开 restTemplate 时添加请求标头?【英文标题】:Spring Security (OAuth): How can I add a request header when restTemplate is not exposed? 【发布时间】:2021-09-05 06:16:41 【问题描述】:

我正在尝试使用 Spring Security 中内置的 OAuth 支持来设置资源服务器。我需要在从资源服务器发送到身份验证服务的每个请求中注入一个新的请求标头。我该怎么做?

用例

Auth 服务位于企业 API Gateway 转发服务之后,如下所示:

Resource API > API Gateway > Auth API

通过 API 网关发送的每个请求都需要一个额外的标头来向网关服务验证客户端。如何注入此标头?否则,Auth API 实现是标准的 OIDC 设置。

我的设置

我已将 spring security oauth2 添加到我的 Gradle 构建中:

    implementation 'org.springframework.security:spring-security-config'
    implementation 'org.springframework.security:spring-security-oauth2-resource-server'
    implementation 'org.springframework.security:spring-security-oauth2-jose'

我在Spring Security中配置了issuer URI,如下:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://auth/api/url

问题

在应用启动时,出现以下异常:

java.lang.IllegalArgumentException: Unable to resolve the Configuration with the provided Issuer of "https://auth/api/url"
    at org.springframework.security.oauth2.jwt.JwtDecoderProviderConfigurationUtils.getConfiguration(JwtDecoderProviderConfigurationUtils.java:99) ~[spring-security-oauth2-jose-5.4.2.jar:5.4.2]

调试JwtDecoderProviderConfigurationUtils 的代码,我发现它失败了,因为配置请求中缺少 API Gateway 标头。

问题是,我不知道如何修改配置工具来注入 API Gateway 标头。请求是内联构建的,仅使用 URI:

                RequestEntity<Void> request = RequestEntity.get(uri).build();
                ResponseEntity<Map<String, Object>> response = rest.exchange(request, STRING_OBJECT_MAP);
                Map<String, Object> configuration = response.getBody();

RestTemplate 从我的应用代码中隐藏,所以我看不到添加客户端拦截器的方法:

    private static final RestTemplate rest = new RestTemplate();

其实整个config utils类都是包级别的访问,所以我真的无能为力:

final class JwtDecoderProviderConfigurationUtils 

关于 OIDC 解决方案的所有其他内容都应该是标准的。如何在不重新发明整个 Spring Security Oauth 解决方案及其所做的所有自动配置的情况下注入所需的标头?

【问题讨论】:

【参考方案1】:

通过设置以下任何属性启用的所有配置:

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri:
          jwk-set-uri:
          jws-algorithm:
          public-key-location:

最终导致 JwtDecoder bean 被 Spring Boot 创建并自动配置(参见 org.springframework.boot:spring-boot-autoconfigure jar 中的 OAuth2ResourceServerJwtConfiguration.JwtDecoderConfiguration)。

控制此过程并避免错误的最简单方法是提供您自己的 bean:

@Bean
JwtDecoder jwtDecoder() 
    // ...

您可以使用JwtDecoderProviderConfigurationUtils 中的代码作为起点,并将您自己的标头添加到您自己的RestTemplate,或者您可以直接提供一个实现并跳过调用您的身份验证服务器。

【讨论】:

以上是关于Spring Security (OAuth):如何在未公开 restTemplate 时添加请求标头?的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security OAuth2:如何为两类用户提供两个单独的登录链接?

Spring security OAuth2 深入解析

Spring 中的 spring-security-oauth2 与 spring-security-oauth2-core

Spring Security OAuth 2 隐式授权 - 不支持刷新令牌

使用 oauth2 在浏览器中登录后访问 REST 服务,使用 java config 访问 Spring Security

org.springframework.security.oauth 和 org.codehaus.spring-security-oauth 有啥区别?