使用 Feign 为计划的跨服务任务启用 OAuth2

Posted

技术标签:

【中文标题】使用 Feign 为计划的跨服务任务启用 OAuth2【英文标题】:Enabling OAuth2 with Feign for scheduled cross-service tasks 【发布时间】:2018-06-10 00:28:25 【问题描述】:

我正在尝试解决一个难题,即为用于跨服务通信的 Feign 客户端启用基于 OAuth2 的身份验证。

在正常情况下,当用户通过 API 推送请求时,我能够从 Spring 的 SecurityContextHolder 获取所需的所有身份验证详细信息(因为它通常会完成其工作并填充所有详细信息对象)并增强 Feign 的 @ 987654326@如下:

public class FeignAccessTokenRelyInterceptor implements RequestInterceptor 
    private static final Logger log = LoggerFactory.getLogger(FeignAccessTokenRelyInterceptor.class);

    @Override
    public void apply(RequestTemplate template) 
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null)
            String tokenValue = null;
            if (auth.getDetails() instanceof OAuth2AuthenticationDetails) 
                OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
                tokenValue = details.getTokenValue();
            
            if (tokenValue == null) 
                log.warn("Current token value is null");
                return;
            
            template.header("Authorization", "Bearer " + tokenValue);
        
    

但是,当涉及到系统内部触发的预定呼叫时,SecurityContext 显然是空的。我通过预先通过客户端凭据流手动请求访问令牌并加载用户详细信息来填充UserInfoTokenServices

OAuth2Authentication authentication = userInfoTokenServices.loadAuthentication(accessToken);
SecurityContextHolder.getContext().setAuthentication(authentication);

但是这样的构造并不能填充OAuth2Authentication.details,我依靠它来获取访问令牌。我尝试扩展OAuth2AuthenticationDetails,但唯一的构造函数需要HttpServletRequest,这很难进入计划任务,并且创建它的虚拟实例感觉是个糟糕的选择。

到目前为止,我认为唯一合适的选择是单独自定义实现详细信息持有者并将其与我拥有的访问令牌一起传递给 OAuth2Authentication。然后在FeignAccessTokenRelyInterceptor领取。

问题

也许还有其他一些选项可以让我将访问令牌存储在安全上下文中并从那里可靠地获取它,以便不生成新的自定义类?

很高兴得到任何帮助。

我研究过的一些相关链接:

How to get custom user info from OAuth2 authorization server /user endpoint Spring Boot / Spring Cloud / Spring Security: How to correctly obtain an OAuth2 Access Token in a scheduled task Spring @FeignClient , OAuth2 and @Scheduled not working How can I authenticate a system user for scheduled processes in Spring?

【问题讨论】:

【参考方案1】:

关于历史,希望能帮助像我这样挣扎的人。

我没有找到比最初更好的方法,并自定义了InternalOAuth2Details 来保存从 Spring 的 OAuth 服务获得的令牌值。然后,在FeignAccessTokenRelyInterceptor 中,我只需检查当前详细信息是否为InternalOAuth2Details 并尝试从中获取令牌值,如下所示:

@Override
public void apply(RequestTemplate template) 
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();

    if (auth != null)
        String tokenValue = null;
        if (auth.getDetails() instanceof OAuth2AuthenticationDetails) 
            OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
            tokenValue = details.getTokenValue();
         else if (auth.getDetails() instanceof InternalOAuth2Details) 
            InternalOAuth2Details details = (InternalOAuth2Details) auth.getDetails();
            tokenValue = details.getTokenValue();
        
        if (tokenValue == null) 
            log.warn("Current token value is null");
            return;
        
        template.header("Authorization", "Bearer " + tokenValue);
    

我敢打赌,这不是最好的解决方案,但目前看来它工作得相当稳定。

【讨论】:

以上是关于使用 Feign 为计划的跨服务任务启用 OAuth2的主要内容,如果未能解决你的问题,请参考以下文章

使用 C# 任务计划库启用/禁用任务

Linux计划任务

多系统集中管理服务器

feign + hystrix 降级

跟我学Spring Cloud(Finchley版)-14-Feign使用Hystrix

一文详解Spring Cloud Feign重试机制