我和你的情况一样,找到了解决办法。首先,为了看到它的实际效果,我创建了一个具有展示实施的存储库 https://github.com/clocken/spring-webclient-oauth2-login-mock下面解释的所有内容。
有没有一种“更干净”的方法来替换我正在使用的 WebClient bean,通过调用我的假远程服务而无需先尝试获取令牌的方法?
我不会更换WebClient
bean 在你的测试中,而是替换ReactiveOAuth2AuthorizedClientManager https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/ReactiveOAuth2AuthorizedClientManager.html豆与模拟。
为此,您必须稍微修改您的MyRemoteServiceClientOauth2Config
。而不是使用现在已弃用的方法UnAuthenticatedServerOAuth2AuthorizedClientRepository https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/web/server/UnAuthenticatedServerOAuth2AuthorizedClientRepository.html你这样配置(这样也比较符合Servlet-Stack 上的记录配置 https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2Client-webclient-servlet):
@Configuration
public class MyRemoteServiceClientOauth2Config {
@Bean
public WebClient webClient(ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth2ClientCredentialsFilter =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(reactiveOAuth2AuthorizedClientManager);
oauth2ClientCredentialsFilter.setDefaultClientRegistrationId("myRemoteService");
return WebClient.builder()
.filter(oauth2ClientCredentialsFilter)
.build();
}
@Bean
public ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager(ReactiveClientRegistrationRepository clientRegistrations,
ReactiveOAuth2AuthorizedClientService authorizedClients) {
AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new AuthorizedClientServiceReactiveOAuth2AuthorizedClientManager(clientRegistrations, authorizedClients);
authorizedClientManager.setAuthorizedClientProvider(
new ClientCredentialsReactiveOAuth2AuthorizedClientProvider());
return authorizedClientManager;
}
}
然后你可以创建一个模拟ReactiveOAuth2AuthorizedClientManager
总是返回一个Mono https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html of an OAuth2AuthorizedClient https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.html像这样:
@TestComponent
@Primary
public class AlwaysAuthorizedOAuth2AuthorizedClientManager implements ReactiveOAuth2AuthorizedClientManager {
@Value("${spring.security.oauth2.client.registration.myRemoteService.client-id}")
String clientId;
@Value("${spring.security.oauth2.client.registration.myRemoteService.client-secret}")
String clientSecret;
@Value("${spring.security.oauth2.client.provider.some-keycloak.token-uri}")
String tokenUri;
/**
* {@inheritDoc}
*
* @return
*/
@Override
public Mono<OAuth2AuthorizedClient> authorize(final OAuth2AuthorizeRequest authorizeRequest) {
return Mono.just(
new OAuth2AuthorizedClient(
ClientRegistration
.withRegistrationId("myRemoteService")
.clientId(clientId)
.clientSecret(clientSecret)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.tokenUri(tokenUri)
.build(),
"some-keycloak",
new OAuth2AccessToken(TokenType.BEARER,
"c29tZS10b2tlbg==",
Instant.now().minus(Duration.ofMinutes(1)),
Instant.now().plus(Duration.ofMinutes(4)))));
}
}
最后@Import
在你的测试中:
@SpringBootTest
@Import(AlwaysAuthorizedOAuth2AuthorizedClientManager.class)
class YourIntegrationTestClass {
// here is your test code
}
相应的src/test/resources/application.yml
看起来像这样:
spring:
security:
oauth2:
client:
registration:
myRemoteService:
authorization-grant-type: client_credentials
client-id: test-client
client-secret: 6b30087f-65e2-4d89-a69e-08cb3c9f34d2 # bogus
provider: some-keycloak
provider:
some-keycloak:
token-uri: https://some.bogus/token/uri
选择
你也可以使用相同的mockserver
您已经在使用模拟您的 REST 资源、模拟授权服务器并响应令牌请求。为此,您需要配置mockserver
as the token-uri
in the src/test/resources/application.yml
或您用来分别为测试提供属性的任何内容。
Notes
注射WebClient
直接地
推荐的提供方式WebClient
在你的豆子中是通过注入WebClient.Builder
,得到预配置的 https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient通过Spring Boot。这也保证了,WebClient
您的测试中的配置与生产中的配置完全相同。您可以声明WebClientCustomizer
豆类进一步配置此构建器 https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-webclient-customization。这就是它在上面提到的我的展示存储库中实现的方式。
Bean 覆盖/优先级@Primary
on a @Bean
里面一个@Configuration
or @TestConfiguration
我也尝试过,发现它并不总是按照人们期望的方式工作,可能是因为 Spring 加载和实例化 bean 定义的顺序。例如,ReactiveOAuth2AuthorizedClientManager
仅当以下情况时才使用模拟@TestConfiguration
is a static nested
测试类中的类,但如果是则不是@Import
编辑。拥有static nested @TestConfiguration
在接口上并用测试类实现它也不起作用。所以,为了避免这样说static nested
我需要的每个集成测试的课程,我宁愿选择@TestComponent
这里介绍的方法。
其他 OAuth 2.0 授权类型
我只测试了我的方法Client Credentials
拨款类型,但我认为它也可以针对其他拨款类型进行调整或扩展。