使用 Feign 客户端 RequestInterceptor 转发请求 header 或安全上下文

Forward a request header or the security context with a Feign client RequestInterceptor

我想用假客户端 RequestInterceptor 转发请求 header,但是在 RequestInterceptor.apply 内,RequestContextHolder.getRequestAttributes()nullSecurityContextHolder.getContext().getAuthentication() 也是(在那里我最终也可以获得我的 header 的价值)。

这在升级到 Spring-Cloud Brixton 之前是有效的,其中 hystrix 命令现在可能 运行 在一个单独的线程中,因为更改为以下参数可以解决问题:

hystrix.command.default.execution.isolation.strategy: SEMAPHORE

现在,如果没有必要,我不太热衷于更改这种默认值,现在有另一种推荐的转发方式 headers 吗?

谢谢

对于 Spring Boot 2+ / Spring Cloud Finchley +,如果您只需要安全上下文,您可以设置以下内容 属性 :

hystrix.shareSecurityContext=true

并且请求拦截器应该可以工作。


对于其他用例或早期版本(非常感谢 Spring Cloud Sleuth 的启发):

"All" 你必须做的是实现一个 HystrixConcurrencyStrategy ,它在每次线程更改时传递信息。 class 在 Sleuth 中做了非常相似的事情是 here

对于我的具体情况,我会:

  1. Callable 包裹在 wrapCallable 中,例如,CallableWithAuthentication class 将在构造时保存当前身份验证
  2. CallableWithAuthenticationcall方法会先恢复之前保存的Authentication,然后调用原来的action,然后清理当前的Authentication,等等。

一旦您的 HystrixConcurrencyStrategy 启动,您的请求拦截器将再次工作,即使有线程隔离。

注意检查项目的其余部分,还有许多其他有趣的工具(例如 RxJava)。

只是为了详细说明@sebastian 的回答

public class RequestContextHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
    return new RequestAttributeAwareCallable<>(callable, RequestContextHolder.getRequestAttributes());
}

static class RequestAttributeAwareCallable<T> implements Callable<T> {

    private final Callable<T> delegate;
    private final RequestAttributes requestAttributes;

    public RequestAttributeAwareCallable(Callable<T> callable, RequestAttributes requestAttributes) {
        this.delegate = callable;
        this.requestAttributes = requestAttributes;
    }

    @Override
    public T call() throws Exception {
        try {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            return delegate.call();
        } finally {
            RequestContextHolder.resetRequestAttributes();
        }
    }
}

}

然后在配置的某处

@PostConstruct
public void init() {
    HystrixPlugins.getInstance().registerConcurrencyStrategy(new RequestContextHystrixConcurrencyStrategy());
}

参考 following post