将请求头转发到Spring+Netflix+Feign中的多个服务调用



我的应用程序中有一堆中间和核心服务。所有服务都是Spring Boot和使用Netflix Library。当用户请求信息时,该请求将/可能通过链中的其他服务,例如:

Client <-> Zuul <-> Service B <-> Service A

我已经将所有服务(A和B(配置为ResourceServer,因此每次访问都需要经过身份验证。当请求访问令牌(从Spring Security Server(并使用它直接从服务a请求信息时,一切都很好。当我使用相同的令牌访问来自服务B(需要服务A(的信息时,我会收到一个"HTTP 401:需要完全身份验证"错误。服务B使用FeignClient呼叫服务a。

经过一些调试,我发现授权标头没有从服务B传递到服务A。服务B正确检查令牌本身,授予对该方法的访问权限,并尝试执行服务A的请求。

我尝试了RequestInterceptor,但没有成功(错误"当前线程的作用域‘请求’未激活"(

@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) {
...
}
}

是否有任何可行的解决方案可以将授权标头从代理函数传递给FeignClient,以便服务A将接收标头并可以对其进行自己的身份验证检查?

找到了一个有效的解决方案。我仍然不知道这是否是"最好"的方法,如果有人有更好的解决方案,如果你分享它,我会很高兴。但目前,这正如预期的那样:

@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());                   
}
};
}

最新更新