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

Posted

技术标签:

【中文标题】使用 Feign 客户端 RequestInterceptor 转发请求标头或安全上下文【英文标题】:Forward a request header or the security context with a Feign client RequestInterceptor 【发布时间】:2016-03-07 21:13:18 【问题描述】:

我想转发一个带有假装客户端 RequestInterceptor 的请求标头,但是在 RequestInterceptor.apply 内,RequestContextHolder.getRequestAttributes()nullSecurityContextHolder.getContext().getAuthentication() 也是如此(我最终也可以获得我的标头的值)。

这在升级到 Spring-Cloud Brixton 之前可以正常工作,现在 hystrix 命令可能必须在单独的线程中运行,因为更改为以下参数可以解决问题:

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

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

谢谢

【问题讨论】:

你可以将@RequestHeader传递给一个feign方法。您还可以使用hystrix.command.<methodname>.execution.isolation.strategy: SEMAPHORE 单独将每个假装调用设置为 SEMAPHORE。 @spencergibb :谢谢,我就是这么想的。我将为我的项目的文档添加注释。 我认为我们希望以一种简单的方式配置线程与信号量的隔离。 @spencergibb :这可能会有所帮助......但根据 netflix 文档,建议使用 THREAD 隔离策略 (github.com/Netflix/Hystrix/wiki/…)。就我而言,我认为更改隔离级别以简化开发体验并不是一个好主意……我们将采用@RequestHeader 解决方案。非常感谢 Spring Cloud 的出色工作:-) @SébastienNussbaumer 你有例子吗?我不太明白您如何访问拦截器中的 RequestHeader,即 apply 方法。我面临一个类似的问题,即线程本地变量由于第二个线程而返回 null。 【参考方案1】:

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

hystrix.shareSecurityContext=true

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


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

“所有”你所要做的就是实现一个HystrixConcurrencyStrategy,它在每次线程更改时传递信息。在 Sleuth 中做类似事情的类是here。

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

    Callable 包装在wrapCallable 中,例如使用CallableWithAuthentication 类,该类在构造时将保持当前身份验证 CallableWithAuthenticationcall 方法将首先恢复之前保存的Authentication,然后调用原始操作,然后清理当前的Authentication,等等。

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

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

【讨论】:

很高兴你喜欢!也许你会为我们贡献一些东西:D @MarcinGrzejszczak:时间是问题,但是嘿,为什么不呢:) 这仅在您从当前线程调用 feignclient 时有效。或者您是否有从另一个线程调用 feign 客户端的配置?我正在使用自定义线程池执行程序,它正在执行一些验证并调用外部服务。但在这种情况下,请求属性不会传播:( 当然@bilak,你必须用你的 ThreadPoolExecutor 做一些类似的事情......看看 spring cloud sleuth,可能有代码可以帮助你做到这一点...... 非常感谢!节省了很多时间)适用于版本云 - Greenwich.RELEASE 和启动 - 2.1.5.RELEASE【参考方案2】:

只是为了详细说明@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

【讨论】:

以上是关于使用 Feign 客户端 RequestInterceptor 转发请求标头或安全上下文的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud之Feign客户端

SpringCloud之Feign:REST客户端

Feign

feign心得

Feign快速入门

Feign