如何在Spring Security中缓存OAuth2令牌introspection请求?
解决Spring Boot OAuth2资源服务器Opaque Token Introspection缓存问题
针对第三方认证服务器不稳定导致的频繁401错误,你可以通过自定义带缓存逻辑的Token校验器来减少introspection请求次数,具体实现步骤如下:
1. 实现带缓存的OpaqueTokenIntrospector
通过委托模式包装默认的Nimbus校验器,结合@Cacheable注解缓存校验成功的token结果:
import org.springframework.cache.annotation.Cacheable; import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; import org.springframework.security.oauth2.server.resource.introspection.NimbusOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.OAuth2IntrospectionException; public class CachingOpaqueTokenIntrospector implements OpaqueTokenIntrospector { private final OpaqueTokenIntrospector delegate; public CachingOpaqueTokenIntrospector(String introspectionUri, String clientId, String clientSecret) { this.delegate = new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); } @Override @Cacheable(value = "oauth2Introspection", key = "#token", condition = "#result != null && #result.isAuthenticated()") public OAuth2AuthenticatedPrincipal introspect(String token) { try { return this.delegate.introspect(token); } catch (OAuth2IntrospectionException e) { // 认证服务器异常时不缓存,直接抛出异常 throw e; } } }
说明:
condition确保只缓存认证成功的token结果,避免缓存无效token- 捕获
OAuth2IntrospectionException,防止第三方服务异常时错误结果被缓存
2. 在安全配置中替换默认校验器
将自定义的缓存校验器注册为Bean,并替换原有的opaqueToken配置:
import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector; @EnableWebSecurity public class ResourceServerConfig extends WebSecurityConfigurerAdapter { private final String introspectionUri; private final String clientId; private final String clientSecret; // 通过构造注入配置参数 public ResourceServerConfig(String introspectionUri, String clientId, String clientSecret) { this.introspectionUri = introspectionUri; this.clientId = clientId; this.clientSecret = clientSecret; } @Bean public OpaqueTokenIntrospector cachingOpaqueTokenIntrospector() { return new CachingOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret); } @Override protected void configure(HttpSecurity http) throws Exception { http .oauth2ResourceServer(oauth2 -> oauth2 .opaqueToken(token -> token.introspector(cachingOpaqueTokenIntrospector())) ); } }
3. 配置缓存管理器
确保Spring Cache已正确配置,推荐使用Caffeine作为缓存实现(轻量且性能优异):
添加Maven依赖
<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency>
配置缓存过期时间(application.yml)
spring: cache: type: caffeine caffeine: spec: expireAfterWrite=10m # 过期时间建议短于token有效期,避免缓存过期token
关键注意事项
- 缓存时间需匹配token的实际有效期,避免缓存过期token导致的授权问题
- 仅缓存认证成功的结果,失败请求直接转发到第三方服务器,保证错误状态实时性
- 若使用Redis等分布式缓存,需确保
OAuth2AuthenticatedPrincipal可序列化
内容的提问来源于stack exchange,提问作者Matheus
相关产品推荐
相关产品推荐

