【问题标题】:How to get oauth2 access token in a spring boot application (not a web application) using spring security 5如何使用 Spring Security 5 在 Spring Boot 应用程序(不是 Web 应用程序)中获取 oauth2 访问令牌
【发布时间】:2020-05-27 00:50:34
【问题描述】:

我需要在我的 Spring Boot 应用程序的服务层获取访问令牌 (grant_type = client_credentials) 以与其他微服务通信(服务到服务交互)。这一层没有spring http session 或auth,我只有client_id、client_secret 和token url。这些属性在 application.properties 中设置为:

spring.security.oauth2.client.registration.auth1.client-id=***
spring.security.oauth2.client.registration.auth1.client-secret=***
spring.security.oauth2.client.registration.auth1.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.auth1.tokenUri=***

这对于 Spring Security OAuth 来说似乎很简单,但对于 Spring security 却无法解决。参考了 spring security 5 的文档,但一切似乎都在 web 界面的上下文中。我知道我可以使用我拥有的信息进行 http 调用以获取令牌,但我想利用该框架...

场景: 让我们将此 Spring Boot 应用程序服务称为 A。还有其他服务可能会调用 A 来处理 http 上的更新或在 A 侦听的主题上发送 kafka 消息。当 A 处理更新/消息时,它需要向服务 B 发送一些数据,这需要访问令牌以进行 authz。这是我需要访问令牌的地方。所以交互本质上是服务-服务,并不特定于用户。

【问题讨论】:

  • OAuth2RestTemplate 是 Spring Security OAuth 的一个 API,一个单独的插件项目。 OP 正在寻求使用 Spring Security 的内置支持。

标签: java spring spring-boot spring-security oauth-2.0


【解决方案1】:

当不在 Web 界面的上下文中时,您需要查看服务层。

来自 Spring Security 的 AuthorizedClientServiceOAuth2AuthorizedClientManager 的 Javadocs:

能够在 {@code HttpServletRequest} 上下文之外运行的 {@link OAuth2AuthorizedClientManager} 的实现,例如在调度/后台线程和/或服务层中。

这里有一个@Bean 定义可能会有所帮助,我将在下面解释:

    @Bean
    OAuth2AuthorizedClientManager authorizedClientManager
            (ClientRegistrationRepository clients) {
        OAuth2AuthorizedClientService service = 
                new InMemoryOAuth2AuthorizedClientService(clients);
        AuthorizedClientServiceOAuth2AuthorizedClientManager manager =
                new AuthorizedClientServiceOAuth2AuthorizedClientManager(clients, service);
        OAuth2AuthorizedClientProvider authorizedClientProvider =
                OAuth2AuthorizedClientProviderBuilder.builder()
                        .clientCredentials()
                        .build();
        manager.setAuthorizedClientProvider(authorizedClientProvider);
        return manager;
    }

OAuth2AuthorizedClientManager 管理授权 OAuth 2.0 客户端定义。这些定义存储在ClientRegistrationRepository 中,ClientRegistrationRepository 的默认实例由 Spring Boot 通过您已经定义的属性创建。

经理通常需要两件事才能发挥作用:

  • 第一个是OAuth2AuthorizedClientService,如果您想将令牌存储在数据库中,这很方便 - 在 Spring Security 5.2 中,唯一的实现是内存中的;但是,似乎 5.3 将附带 a JDBC implementation

  • 第二个是OAuth2AuthorizedClientProvider,它实际执行令牌请求,例如您想要制作的客户端凭据。

创建此管理器后,您可以将其连接到您的网络客户端:

    @Bean
    WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
        ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
                new ServletOAuth2AuthorizedClientExchangeFilterFunction
                        (authorizedClientManager);
        oauth2.setDefaultClientRegistrationId("auth1");
        return WebClient.builder()
                .apply(oauth2.oauth2Configuration())
                .build();
    }

上面使用的交换过滤器功能是将不记名令牌添加到Authorization 标头的东西。它调用管理器向它索要令牌,管理器从服务中提取它。如果它已过期,经理会要求提供者刷新它。现在,使用新令牌,管理器将其交还给过滤器以将其添加到请求中。

【讨论】:

  • 谢谢!您是否建议使用 Spring Boot 提供的默认 WebClient.Builder 来创建 webclient bean?另外我假设在任何地方注入这个 webclient 是安全的,因为它是线程安全的。更正,你的意思可能是AuthorizedClientServerOAuth2AuthorizedClientManager->AuthorizedClientServiceOAuth2AuthorizedClientManager
  • 我还没有玩太多自动装配 WebClient.Builder,但我认为 Brian Clozel 在这里提供了一些有趣的观点:stackoverflow.com/a/54144043/2243324 - 我给出的答案遵循 Spring Security 示例中的模式,但肯定有可能在这个方向上得到改进。是的,多个 bean 依赖于同一个 Web 客户端实例应该可以正常工作。
  • 对我来说,身份验证服务器位于代理后面,因此令牌调用会一直超时。我在这里提到了乔的评论github.com/spring-projects/spring-security/issues/… 我们可以为 OAuth2AuthorizedClientProvider 类设置一个 webclient 吗?任何帮助将不胜感激!
  • @Denson,我建议您提出一个单独的问题,并详细说明您的情况。例如,我不清楚为什么在代理后面会导致超时。一个单独的问题将有助于了解额外需要的细节。谢谢!
猜你喜欢
  • 2020-01-26
  • 2016-02-07
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 2018-02-05
  • 2017-07-08
  • 2018-02-22
  • 2021-08-22
相关资源
最近更新 更多