alm*_*777 12 spring-security spring-security-oauth2 spring-cloud-feign
我正在尝试编写一个访问公共 REST API 的程序。为了让我能够使用它,我需要提供 OAuth2 令牌。
我的应用程序使用 Spring Boot 2.4.2 和 Spring Cloud 版本 2020.0.1。应用程序本身每 24 小时调用一次 REST API,下载数据并将其存储在数据库中。不同的微服务在其他时间点使用这些数据,并且需要每天刷新数据。
我的方法是使用 OpenFeign 声明使用 REST API 的 REST 客户端并为其提供 OAuth2 令牌。这是一个非常常见的问题,因此我认为机器对机器的client_credentials工作流程已有详细记录。
事实上,我确实找到了一个使用 OpenFeign 执行此操作的简单示例 - 这里: https: //github.com/netshoes/sample-feign-oauth2-interceptor/blob/master/src/main/java/com/sample/feign /oauth2/interceptor/OrderFeignClientConfiguration.java
TL;DR:尝试编写需要 OAuth2 令牌(client_credentials 授予类型)的机器对机器微服务。
这是我的第一次尝试,但不幸的是,随着新的 Spring Security 版本的出现,我似乎无法实例化OAuth2FeignRequestInterceptor,我可能遇到了包问题。然后我继续研究 Spring Security 的文档和新的 OAuth2 重写,可以在这里找到:https ://docs.spring.io/spring-security/site/docs/5.1.2.RELEASE/reference/htmlsingle /#oauth2client .
我的方法是通过RequestInterceptor添加 Authorization Bearer 标头,将当前的 OAuth2 令牌注入 OpenFeign 客户端的请求中。我的假设是,我可以使用 Spring Security OAuth2 层或多或少自动地检索此信息。
使用文档,我尝试OAuth2RegisteredClient为我的拦截器提供一个 bean 以及一个 type 的 bean OAuth2AccessToken- 两者都不起作用。我的最后一次尝试看起来像这样,被视为一种万岁玛丽,一种方法:
@Bean
public OAuth2AccessToken apiAccessToken(
@RegisteredOAuth2AuthorizedClient("MY_AWESOME_PROVIDER") OAuth2AuthorizedClient authorizedClient) {
return authorizedClient.getAccessToken();
}
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为RegisteredOAuth2AuthorizedClient需要用户会话,以免发生null。我还在 Stackoverflow 上看到其他人尝试了相同的方法,但他们实际上是在Controller(=> Resolving OAuth2AuthorizedClient as a Spring bean )
我还尝试了一些我在这里找到的方法:
OAuth2FeignRequestInterceptorOAuth2FeignRequestInterceptor我的假设是我可以以某种方式使用 Spring Security 5 来解决这个问题,但我根本不知道如何实际做到这一点。在我看来,我发现的大多数教程和代码示例实际上都需要用户会话,或者对于 Spring Security 5 来说已经过时了。
看来我真的错过了一些东西,我希望有人能指出我正确的方向,关于如何实现这一目标的教程或书面文档。
我尝试提供一个OAuth2AuthorizedClientManager如本例所示的(https://github.com/jgrandja/spring-security-oauth-5-2-migrate)。为此,我注册了OAuth2AuthorizedClientManager以下示例代码:
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials()
.password()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
Run Code Online (Sandbox Code Playgroud)
并为我提供了它,RequestInterceptor如下所示:
@Bean
public RequestInterceptor requestInterceptor(OAuth2AuthorizedClientManager clientManager) {
return new OAuthRequestInterceptor(clientManager);
}
Run Code Online (Sandbox Code Playgroud)
最后我写了拦截器,如下所示:
private String getAccessToken() {
OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest.withClientRegistrationId(appClientId)
// .principal(appClientId) // if this is not set, I receive "principal cannot be null" (or empty)
.build();
return Optional.ofNullable(authorizedClientManager)
.map(clientManager -> clientManager.authorize(request))
.map(OAuth2AuthorizedClient::getAccessToken)
.map(AbstractOAuth2Token::getTokenValue)
.orElseThrow(OAuth2AccessTokenRetrievalException::failureToRetrieve);
}
@Override
public void apply(RequestTemplate template) {
log.debug("FeignClientInterceptor -> apply CALLED");
String token = getAccessToken();
if (token != null) {
String bearerString = String.format("%s %s", BEARER, token);
template.header(HttpHeaders.AUTHORIZATION, bearerString);
log.debug("set the template header to this bearer string: {}", bearerString);
} else {
log.error("No bearer string.");
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行代码时,我可以在控制台中看到“FeignClientInterceptor -> apply called”输出,然后是异常:
Caused by: java.lang.IllegalArgumentException: servletRequest cannot be null
我的假设是我收到此消息,因为我没有活动的用户会话。因此,在我看来,我绝对需要一个来解决这个问题——而我在机器对机器通信中没有这个问题。
这是一个常见的用例,所以我确信我一定在某个时候犯了错误。
也许我的包裹弄错了?
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation 'org.springframework.boot:spring-boot-starter-jooq'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
Run Code Online (Sandbox Code Playgroud)
小智 5
根据文档需要使用 AuthorizedClientServiceOAuth2AuthorizedClientManager 而不是 DefaultOAuth2AuthorizedClientManager
在 HttpServletRequest 上下文之外进行操作时,请改用 AuthorizedClientServiceOAuth2AuthorizedClientManager。
| 归档时间: |
|
| 查看次数: |
29068 次 |
| 最近记录: |