使用 Feign RequestInterceptor 无法访问安全上下文
Unreachable security context using Feign RequestInterceptor
目标是使用 RequestInterceptor 从安全上下文附加一些数据,但问题是调用 SecurityContextHolder.getContext().getAuthentication()
总是 returns null,即使它不是 null(我确定 100%) .
据我了解,这是因为拦截器已创建并在其他线程中 运行。
我怎样才能解决这个问题并从安全上下文中获取实际数据?
我的服务:
@FeignClient(value = "api", configuration = { FeignConfig.class })
public interface DocumentService {
@RequestMapping(value = "/list", method = RequestMethod.GET)
DocumentListOperation list();
}
我的FeignConfig class:
@Bean
public RequestInterceptor requestInterceptor() {
return new HeaderInterceptor(userService);
}
public class HeaderInterceptor implements RequestInterceptor {
private UserService userService;
public HeaderInterceptor(UserService userService) {
this.userService = userService;
}
@Override
public void apply(RequestTemplate requestTemplate) {
Authentication a = SecurityContextHolder.getContext().getAuthentication()
requestTemplate.header("authentication", a.toString());
}
}
我设法弄明白了,多亏了我找到的文章 here
首先你需要初始化HystrixRequestContext HystrixRequestContext.initializeContext();
。
您必须创建自己的上下文,您将在其中存储需要传递给 Hystrix 子线程的信息。
示例如下:
public class UserHystrixRequestContext {
private static final HystrixRequestVariableDefault<User> userContextVariable = new HystrixRequestVariableDefault<>();
private UserHystrixRequestContext() {}
public static HystrixRequestVariableDefault<User> getInstance() {
return userContextVariable;
}
}
您必须注册新的并发策略来包装 Callable 接口
@Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
public CustomHystrixConcurrencyStrategy() {
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
return new HystrixContextWrapper<T>(callable);
}
public static class HystrixContextWrapper<V> implements Callable<V> {
private HystrixRequestContext hystrixRequestContext;
private Callable<V> delegate;
public HystrixContextWrapper(Callable<V> delegate) {
this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
this.delegate = delegate;
}
@Override
public V call() throws Exception {
HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
try {
HystrixRequestContext.setContextOnCurrentThread(this.hystrixRequestContext);
return this.delegate.call();
} finally {
HystrixRequestContext.setContextOnCurrentThread(existingState);
}
}
}
}
因此在调用 Callable 对象之前,我们将新线程的上下文设置为父线程的上下文。
完成后,您应该能够在 Hystrix 子线程中访问新定义的上下文
User = UserHystrixRequestContext.getInstance().get();
希望对某人有所帮助。
目标是使用 RequestInterceptor 从安全上下文附加一些数据,但问题是调用 SecurityContextHolder.getContext().getAuthentication()
总是 returns null,即使它不是 null(我确定 100%) .
据我了解,这是因为拦截器已创建并在其他线程中 运行。
我怎样才能解决这个问题并从安全上下文中获取实际数据?
我的服务:
@FeignClient(value = "api", configuration = { FeignConfig.class })
public interface DocumentService {
@RequestMapping(value = "/list", method = RequestMethod.GET)
DocumentListOperation list();
}
我的FeignConfig class:
@Bean
public RequestInterceptor requestInterceptor() {
return new HeaderInterceptor(userService);
}
public class HeaderInterceptor implements RequestInterceptor {
private UserService userService;
public HeaderInterceptor(UserService userService) {
this.userService = userService;
}
@Override
public void apply(RequestTemplate requestTemplate) {
Authentication a = SecurityContextHolder.getContext().getAuthentication()
requestTemplate.header("authentication", a.toString());
}
}
我设法弄明白了,多亏了我找到的文章 here
首先你需要初始化HystrixRequestContext HystrixRequestContext.initializeContext();
。
您必须创建自己的上下文,您将在其中存储需要传递给 Hystrix 子线程的信息。
示例如下:
public class UserHystrixRequestContext {
private static final HystrixRequestVariableDefault<User> userContextVariable = new HystrixRequestVariableDefault<>();
private UserHystrixRequestContext() {}
public static HystrixRequestVariableDefault<User> getInstance() {
return userContextVariable;
}
}
您必须注册新的并发策略来包装 Callable 接口
@Component
public class CustomHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
public CustomHystrixConcurrencyStrategy() {
HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
}
@Override
public <T> Callable<T> wrapCallable(Callable<T> callable) {
return new HystrixContextWrapper<T>(callable);
}
public static class HystrixContextWrapper<V> implements Callable<V> {
private HystrixRequestContext hystrixRequestContext;
private Callable<V> delegate;
public HystrixContextWrapper(Callable<V> delegate) {
this.hystrixRequestContext = HystrixRequestContext.getContextForCurrentThread();
this.delegate = delegate;
}
@Override
public V call() throws Exception {
HystrixRequestContext existingState = HystrixRequestContext.getContextForCurrentThread();
try {
HystrixRequestContext.setContextOnCurrentThread(this.hystrixRequestContext);
return this.delegate.call();
} finally {
HystrixRequestContext.setContextOnCurrentThread(existingState);
}
}
}
}
因此在调用 Callable 对象之前,我们将新线程的上下文设置为父线程的上下文。
完成后,您应该能够在 Hystrix 子线程中访问新定义的上下文
User = UserHystrixRequestContext.getInstance().get();
希望对某人有所帮助。