如何区分 RequestInterceptor 中 two/multiple 端点之间的 headers
How to differentiate headers between two/multiple endpoints in a RequestInterceptor
您好,我是 Java 和 Springboot 的新手。我目前正在使用 API,在发出 POST 请求之前,我需要生成一个 Bearer 令牌。为了生成 Bearer 令牌,我需要将我的基本身份验证凭据传递到“/oauth/token”端点。我的应用程序在传递我的基本身份验证凭据时遇到问题,因为当我点击“/v1/some-endpoint”时,我被拒绝授权,因为 Bearer 令牌为空。
这是我最初的解决方案,我认为我可以检查拦截器中的 url,然后执行以下行,但在调试之后,它似乎并没有命中该行。
有什么我遗漏或没有正确实施的吗?我是否没有正确实施 Basic Auth 端点?如果您需要更多信息,请与我们联系。谢谢
@Profile("!offline")
@FeignClient(
value = "someClient",
url = "${someProperty.url}",
configuration = SomeClient.SomeClientConfig.class)
public interface someClient {
@PostMapping("/v1/some-endpoint")
void redeemSomething(someRequestBody data);
@PostMapping("/oauth/token")
static BasicAuthResponse getBasicAuthToken() {
return new BasicAuthResponse();
}
@AllArgsConstructor
class SomeClientConfig extends BaseClientConfig {
private final SomeProperties properties;
private final SomeAuthTokenSupplier tokenSupplier = new SomeAuthTokenSupplier();
@Bean
@Override
public CloseableHttpClient apacheClient() {
return apacheClientFactory(properties.getUseProxy());
}
@Bean
public RequestInterceptor someAuthInterceptor() {
return template -> {
if(template.url().equals("/oauth/token")) {
String authToken = Base64Utils.encodeToString((properties.getCredentials().getUser() + ":" + properties.getCredentials().getUser()).getBytes(Charset.forName("UTF-8")));
template.header("Authorization", authToken);
}
template.header("Authorization", String.format("Bearer %s", tokenSupplier.getToken()));
};
}
private class SomeAuthTokenSupplier {
private volatile String token;
private volatile long retrievedOn = -1L;
String getToken() {
if (updateTokenRequired()) {
synchronized (this) {
if (updateTokenRequired()) {
BasicAuthResponse tokenResponse = getBasicAuthToken();
token = tokenResponse.getAccess_token(); // new token from some api should be assigned here
retrievedOn = Instant.now().toEpochMilli();
}
}
}
return token;
}
private boolean updateTokenRequired() {
return token == null || LocalDateTime.now().minusHours(8L).isAfter(LocalDateTime.ofInstant(Instant.ofEpochMilli(retrievedOn), ZoneId.systemDefault()));
}
}
@Override
public Retryer retryer() {
return new ClientRetry(250L, 2, 3) {
@Override
public void continueOrPropagate(RetryableException e) {
if (e.status() == 401 || e.status() == 403) {
tokenSupplier.token = null;
}
super.continueOrPropagate(e);
}
};
}
}
}
值得使用标准 Spring 安全 OAuth2 客户端功能来支持 Feign 客户端中的授权
查看文档和代码示例:https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client
更新
查看另一个代码示例:https://github.com/int128/feign-oauth2-example
如果多个服务端点需要不同的身份验证,那么值得拥有多个 Feign 客户端,每个客户端都有自己的配置
您好,我是 Java 和 Springboot 的新手。我目前正在使用 API,在发出 POST 请求之前,我需要生成一个 Bearer 令牌。为了生成 Bearer 令牌,我需要将我的基本身份验证凭据传递到“/oauth/token”端点。我的应用程序在传递我的基本身份验证凭据时遇到问题,因为当我点击“/v1/some-endpoint”时,我被拒绝授权,因为 Bearer 令牌为空。
这是我最初的解决方案,我认为我可以检查拦截器中的 url,然后执行以下行,但在调试之后,它似乎并没有命中该行。
有什么我遗漏或没有正确实施的吗?我是否没有正确实施 Basic Auth 端点?如果您需要更多信息,请与我们联系。谢谢
@Profile("!offline")
@FeignClient(
value = "someClient",
url = "${someProperty.url}",
configuration = SomeClient.SomeClientConfig.class)
public interface someClient {
@PostMapping("/v1/some-endpoint")
void redeemSomething(someRequestBody data);
@PostMapping("/oauth/token")
static BasicAuthResponse getBasicAuthToken() {
return new BasicAuthResponse();
}
@AllArgsConstructor
class SomeClientConfig extends BaseClientConfig {
private final SomeProperties properties;
private final SomeAuthTokenSupplier tokenSupplier = new SomeAuthTokenSupplier();
@Bean
@Override
public CloseableHttpClient apacheClient() {
return apacheClientFactory(properties.getUseProxy());
}
@Bean
public RequestInterceptor someAuthInterceptor() {
return template -> {
if(template.url().equals("/oauth/token")) {
String authToken = Base64Utils.encodeToString((properties.getCredentials().getUser() + ":" + properties.getCredentials().getUser()).getBytes(Charset.forName("UTF-8")));
template.header("Authorization", authToken);
}
template.header("Authorization", String.format("Bearer %s", tokenSupplier.getToken()));
};
}
private class SomeAuthTokenSupplier {
private volatile String token;
private volatile long retrievedOn = -1L;
String getToken() {
if (updateTokenRequired()) {
synchronized (this) {
if (updateTokenRequired()) {
BasicAuthResponse tokenResponse = getBasicAuthToken();
token = tokenResponse.getAccess_token(); // new token from some api should be assigned here
retrievedOn = Instant.now().toEpochMilli();
}
}
}
return token;
}
private boolean updateTokenRequired() {
return token == null || LocalDateTime.now().minusHours(8L).isAfter(LocalDateTime.ofInstant(Instant.ofEpochMilli(retrievedOn), ZoneId.systemDefault()));
}
}
@Override
public Retryer retryer() {
return new ClientRetry(250L, 2, 3) {
@Override
public void continueOrPropagate(RetryableException e) {
if (e.status() == 401 || e.status() == 403) {
tokenSupplier.token = null;
}
super.continueOrPropagate(e);
}
};
}
}
}
值得使用标准 Spring 安全 OAuth2 客户端功能来支持 Feign 客户端中的授权
查看文档和代码示例:https://docs.spring.io/spring-security/site/docs/current/reference/html5/#oauth2client
更新
查看另一个代码示例:https://github.com/int128/feign-oauth2-example
如果多个服务端点需要不同的身份验证,那么值得拥有多个 Feign 客户端,每个客户端都有自己的配置