将请求 headers 转发到 Spring + Netflix + Feign 中的多个服务调用
Forward request headers to multiple service calls in Spring + Netflix + Feign
我的应用程序中有一堆中间和核心服务。所有服务都是 Spring 启动并使用 Netflix 库。当用户请求信息时,请求 will/might 传递链中的其他服务 eg:
Client <-> Zuul <-> Service B <-> Service A
我已将所有服务(A 和 B)配置为 ResourceServer,以便每次访问都需要进行身份验证。当请求访问令牌(来自 Spring 安全服务器)并使用它直接从服务 A 请求信息时,一切正常。当我使用相同的令牌从服务 B(需要服务 A)访问信息时,我收到 "HTTP 401: Full authentification is required" 错误。服务B使用FeignClient调用服务A。
经过一些调试,我发现 Authorization-Header 没有从服务 B 传递到服务 A。服务 B 正确检查令牌本身,授予对该方法的访问权限并尝试执行请求服务 A.
我尝试了 RequestInterceptor 但没有成功(错误 "Scope 'request' is not active for the current thread")
@Component
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";
private final OAuth2ClientContext oauth2ClientContext;
public OAuth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext) {
Assert.notNull(oauth2ClientContext, "Context can not be null");
this.oauth2ClientContext = oauth2ClientContext;
}
@Override
public void apply(RequestTemplate template) {
if (template.headers().containsKey(AUTHORIZATION_HEADER)) {
...
} else if (oauth2ClientContext.getAccessTokenRequest().getExistingToken() == null) {
...
} else {
template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE,
oauth2ClientContext.getAccessTokenRequest().getExistingToken().toString()));
}
}
}
这是一个使用 FeignClient 的示例代理函数:
@Autowired
private CategoryClient cat;
@HystrixCommand(fallbackMethod = "getAllFallback", commandProperties = {@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2") })
@GetMapping("/category")
public ResponseEntity<List<Category>> getAll() {
try {
ResponseEntity<List<Category>> categories = this.cat.getAll();
...
return categories;
} catch(Exception e) {
...
}
}
是否有任何可行的解决方案将 Authorization-Header 从代理函数传递到 FeignClient,以便服务 A 将收到 header 并可以对其进行自己的身份验证?
找到了可行的解决方案。我仍然不知道这是否是 "best" 的方法,如果有人有更好的解决方案,我会很高兴与您分享。但就目前而言,这是按预期工作的:
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header("Authorization", "Bearer " + details.getTokenValue());
}
};
}
我的应用程序中有一堆中间和核心服务。所有服务都是 Spring 启动并使用 Netflix 库。当用户请求信息时,请求 will/might 传递链中的其他服务 eg:
Client <-> Zuul <-> Service B <-> Service A
我已将所有服务(A 和 B)配置为 ResourceServer,以便每次访问都需要进行身份验证。当请求访问令牌(来自 Spring 安全服务器)并使用它直接从服务 A 请求信息时,一切正常。当我使用相同的令牌从服务 B(需要服务 A)访问信息时,我收到 "HTTP 401: Full authentification is required" 错误。服务B使用FeignClient调用服务A。
经过一些调试,我发现 Authorization-Header 没有从服务 B 传递到服务 A。服务 B 正确检查令牌本身,授予对该方法的访问权限并尝试执行请求服务 A.
我尝试了 RequestInterceptor 但没有成功(错误 "Scope 'request' is not active for the current thread")
@Component
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";
private final OAuth2ClientContext oauth2ClientContext;
public OAuth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext) {
Assert.notNull(oauth2ClientContext, "Context can not be null");
this.oauth2ClientContext = oauth2ClientContext;
}
@Override
public void apply(RequestTemplate template) {
if (template.headers().containsKey(AUTHORIZATION_HEADER)) {
...
} else if (oauth2ClientContext.getAccessTokenRequest().getExistingToken() == null) {
...
} else {
template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE,
oauth2ClientContext.getAccessTokenRequest().getExistingToken().toString()));
}
}
}
这是一个使用 FeignClient 的示例代理函数:
@Autowired
private CategoryClient cat;
@HystrixCommand(fallbackMethod = "getAllFallback", commandProperties = {@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2") })
@GetMapping("/category")
public ResponseEntity<List<Category>> getAll() {
try {
ResponseEntity<List<Category>> categories = this.cat.getAll();
...
return categories;
} catch(Exception e) {
...
}
}
是否有任何可行的解决方案将 Authorization-Header 从代理函数传递到 FeignClient,以便服务 A 将收到 header 并可以对其进行自己的身份验证?
找到了可行的解决方案。我仍然不知道这是否是 "best" 的方法,如果有人有更好的解决方案,我会很高兴与您分享。但就目前而言,这是按预期工作的:
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header("Authorization", "Bearer " + details.getTokenValue());
}
};
}