Spring Boot 2.7.6中OAuth2RestTemplate令牌过期未刷新致401问题
我们的应用基于Spring Boot 2.7.6和Spring Cloud 2021.0.5构建,部署在VMWare Tanzu平台,通过Feign客户端配合OAuth2RestTemplate实现与Hybris/SAP Commerce应用的API认证。当前遇到**间歇性401 Unauthorized(无效令牌)**异常,具体特征:
- 相同代码在旧版Spring Boot生产环境运行正常,仅升级到SB-2.7.6后出现该问题
- 失效实例必须重启才能恢复,且故障仅发生在单个实例上
- 排查发现不同实例使用的访问令牌各不相同
相关代码示例
Feign接口定义
@FeignClient(name = "hybris", url = "${URL}", fallbackFactory = HybrisClientFallbackFactory.class, configuration = { HybrisFeignClientRequestInterceptor.class, FeignRetryConfiguration.class, FeignRetryer.class}) public interface HybrisClient { @PostMapping("/epInternal/order/order-history") OrderHistoryResponse getOrderHistory(OrderHistoryRequest orderHistoryRequest); }
Feign请求拦截器
public class HybrisFeignClientRequestInterceptor { @Qualifier("hybrisOAuth2RestTemplate") private final OAuth2RestTemplate hybrisOAuth2RestTemplate; @Bean public RequestInterceptor apigeeHybrisOauth2RequestInterceptor() { return (requestTemplate) -> { requestTemplate.header("Authorization", new String[]{String.format("%s %s", "Bearer", this.hybrisOAuth2RestTemplate.getAccessToken().getValue())}); requestTemplate.header("x-api-key", new String[]{clientId}); }; } }
可能的原因与排查方向
OAuth2RestTemplate令牌管理的线程安全问题
Spring Boot 2.7.x对Spring Security OAuth2依赖版本做了调整,OAuth2RestTemplate的自动刷新逻辑在多线程场景下可能存在漏洞,单个实例中令牌过期后未正确触发刷新,导致持续使用无效令牌。Feign拦截器Bean作用域冲突
当前RequestInterceptorBean默认是单例模式,若OAuth2RestTemplate的状态管理不当,多线程环境下可能出现令牌复用、未及时更新的情况。Tanzu平台实例的网络/授权服务连接异常
单个实例故障可能是该实例与OAuth2授权服务器的网络连接异常,导致令牌刷新失败却未抛出异常,进而一直使用过期令牌。令牌过期时间与刷新阈值不匹配
检查Hybris端的令牌过期配置,若Spring侧的刷新触发阈值设置不合理,可能在令牌已过期后才启动刷新流程,导致短时间内使用无效令牌。
建议解决方案
替换OAuth2RestTemplate为Spring Security 5+的WebClient
Spring Security OAuth2已逐步弃用OAuth2RestTemplate,推荐使用WebClient结合OAuth2AuthorizedClientManager实现令牌管理,其线程安全性和自动刷新机制更可靠。调整拦截器Bean的作用域
将RequestInterceptor改为@RequestScope或@Scope("prototype"),确保每次请求都能获取最新令牌,需注意评估对性能的影响。添加令牌有效性校验与刷新重试逻辑
在拦截器中增加令牌过期时间校验,若令牌即将过期或已过期,主动触发刷新;同时为令牌获取流程添加重试机制,处理临时网络异常。开启OAuth2日志排查
配置Spring Security OAuth2的DEBUG级别日志,跟踪令牌获取、刷新的完整流程,定位单个实例的令牌异常细节。
内容的提问来源于stack exchange,提问作者Pramod H G

