如何在 spring webflux 中的 webClient 实例化期间设置一次访问令牌?
How to set the access token once during the instanciation of the webClient in spring webflux?
我尝试在 spring webflux 中将 WebClient 与 oauth2 结合使用。我从 url 访问令牌中获取令牌并将其设置到网络客户端中。但我不喜欢在每次调用其他安全端点时都获取此访问令牌。意味着我只想在 webclient 的实例化期间和访问令牌过期时第一次获取它。
这是我正在使用的代码:
@Configuration
public class OauthEmployeConfig{
/**
** ... String baseUrl, String accessUrl for the access token url
**/
@Bean
public WebClient webClient(UserRegistration userRegistr) {
ClientRequest clientRequest = ClientRequest
.create(HttpMethod.POST, URI.create(accessUrl))
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.headers(headers -> headers.setBasicAuth(userRegistr.getClientId(), userRegistr.getClientSecret()))
.body(BodyInserters.fromFormData("grant_type", userRegistr.getAuthorizGrantType())
.with("scope", userRegistr.getScope().replaceAll(",", "")))
.build();
return WebClient.builder()
.baseUrl(baseUrl)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.filter((request, next) -> next.exchange(clientRequest)
.flatMap(response -> response.body(org.springframework.security.oauth2.core.web.reactive.function.OAuth2BodyExtractors.oauth2AccessTokenResponse()))
.map(accessToken -> accessToken.getAccessToken().getTokenValue())
.map(token -> setBearer(request, token))
.flatMap(next::exchange))
.filter(logRequest())
.filter(handleResponseError())
.build();
}
private ClientRequest setBearer(ClientRequest request, String token) {
return ClientRequest.from(request)
.header("Authorization", "Bearer " + token).build();
}
private static ExchangeFilterFunction handleResponseError() {
return ExchangeFilterFunction.ofResponseProcessor(
response -> response.statusCode().isError()
? response.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(new RuntimeException(errorBody, response.statusCode())))
: Mono.just(response));
}
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOG.info("{}={}", name, value)));
return Mono.just(clientRequest);
});
}
}
我关注了 this toturial and also spring doc,我不得不更改我的代码。
所以我的代码看起来像:
application.properties
spring.security.oauth2.client.registration.chris.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.chris.client-id=chris-client-id
spring.security.oauth2.client.registration.chris.client-secret=chris-secret
spring.security.oauth2.client.provider.chris.token-uri=http://localhost:8085/oauth/token
配置class:
@Configuration
public OauthEmployeConfig {
@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("chris");
oauth.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.filter(oauth)
.filter(logRequest())
.filter(handleResponseError())
.build();
}
private static ExchangeFilterFunction handleResponseError() {
return ExchangeFilterFunction.ofResponseProcessor(
response -> response.statusCode().isError() ?
response.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(new RunTimeException(errorBody, response.statusCode()))) :
Mono.just(response));
}
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
// To log the headers details like Token ...
clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOGGER.info("{}={}", name, value)));
return Mono.just(clientRequest);
});
}
}
通过 webClient 调用:
...
webClient.get()
.uri("http://localhost:8084/retrieve-resource")
.retrieve()
...
这种方法当然会在访问令牌过期后通过刷新令牌更新访问令牌。
请参考: 因为 class UnAuthenticatedServerOAuth2AuthorizedClientRepository 已弃用。
我尝试在 spring webflux 中将 WebClient 与 oauth2 结合使用。我从 url 访问令牌中获取令牌并将其设置到网络客户端中。但我不喜欢在每次调用其他安全端点时都获取此访问令牌。意味着我只想在 webclient 的实例化期间和访问令牌过期时第一次获取它。
这是我正在使用的代码:
@Configuration
public class OauthEmployeConfig{
/**
** ... String baseUrl, String accessUrl for the access token url
**/
@Bean
public WebClient webClient(UserRegistration userRegistr) {
ClientRequest clientRequest = ClientRequest
.create(HttpMethod.POST, URI.create(accessUrl))
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
.headers(headers -> headers.setBasicAuth(userRegistr.getClientId(), userRegistr.getClientSecret()))
.body(BodyInserters.fromFormData("grant_type", userRegistr.getAuthorizGrantType())
.with("scope", userRegistr.getScope().replaceAll(",", "")))
.build();
return WebClient.builder()
.baseUrl(baseUrl)
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
.filter((request, next) -> next.exchange(clientRequest)
.flatMap(response -> response.body(org.springframework.security.oauth2.core.web.reactive.function.OAuth2BodyExtractors.oauth2AccessTokenResponse()))
.map(accessToken -> accessToken.getAccessToken().getTokenValue())
.map(token -> setBearer(request, token))
.flatMap(next::exchange))
.filter(logRequest())
.filter(handleResponseError())
.build();
}
private ClientRequest setBearer(ClientRequest request, String token) {
return ClientRequest.from(request)
.header("Authorization", "Bearer " + token).build();
}
private static ExchangeFilterFunction handleResponseError() {
return ExchangeFilterFunction.ofResponseProcessor(
response -> response.statusCode().isError()
? response.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(new RuntimeException(errorBody, response.statusCode())))
: Mono.just(response));
}
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOG.info("{}={}", name, value)));
return Mono.just(clientRequest);
});
}
}
我关注了 this toturial and also spring doc,我不得不更改我的代码。
所以我的代码看起来像:
application.properties
spring.security.oauth2.client.registration.chris.authorization-grant-type=client_credentials
spring.security.oauth2.client.registration.chris.client-id=chris-client-id
spring.security.oauth2.client.registration.chris.client-secret=chris-secret
spring.security.oauth2.client.provider.chris.token-uri=http://localhost:8085/oauth/token
配置class:
@Configuration
public OauthEmployeConfig {
@Bean
WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(
clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("chris");
oauth.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder()
.filter(oauth)
.filter(logRequest())
.filter(handleResponseError())
.build();
}
private static ExchangeFilterFunction handleResponseError() {
return ExchangeFilterFunction.ofResponseProcessor(
response -> response.statusCode().isError() ?
response.bodyToMono(String.class)
.flatMap(errorBody -> Mono.error(new RunTimeException(errorBody, response.statusCode()))) :
Mono.just(response));
}
private static ExchangeFilterFunction logRequest() {
return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
// To log the headers details like Token ...
clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOGGER.info("{}={}", name, value)));
return Mono.just(clientRequest);
});
}
}
通过 webClient 调用:
...
webClient.get()
.uri("http://localhost:8084/retrieve-resource")
.retrieve()
...
这种方法当然会在访问令牌过期后通过刷新令牌更新访问令牌。
请参考: 因为 class UnAuthenticatedServerOAuth2AuthorizedClientRepository 已弃用。