Spring Security 中缓存 Introspect 请求

Spring Security 中缓存 Introspect 请求

本文档介绍了如何在 spring Security OAuth2 资源服务器中缓存 Opaque Token Introspection 请求,以提高系统在认证服务器不稳定时的可用性和性能。通过自定义 OpaqueTokenIntrospector 并集成缓存机制,可以有效减少对认证服务器的依赖,避免频繁的 401 错误,提升用户体验。

在使用 spring boot 构建 OAuth2 资源服务器时,通常需要与认证服务器进行交互以验证 Opaque Token 的有效性。当认证服务器出现不稳定情况时,频繁的 Introspection 请求会导致资源服务器性能下降,并可能出现大量的 401 错误。为了解决这个问题,我们可以通过缓存 Introspection 请求的结果来减少对认证服务器的依赖。

自定义 OpaqueTokenIntrospector

spring security 提供了 OpaqueTokenIntrospector 接口,用于从认证服务器获取 Token 的元数据。我们可以通过自定义该接口的实现来集成缓存逻辑。

首先,在 Spring Security 配置中暴露一个 OpaqueTokenIntrospector 的 Bean:

@Bean public OpaqueTokenIntrospector introspector() {     return new CustomOpaqueTokenIntrospector(this.introspectionUri, this.clientId, this.clientSecret); }

接下来,创建 CustomOpaqueTokenIntrospector 类,实现 OpaqueTokenIntrospector 接口,并在其中集成缓存逻辑。这里我们使用 org.ehcache 作为缓存的实现。

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.ehcache.Cache; import org.ehcache.CacheManager; import org.ehcache.config.builders.CacheConfigurationBuilder; import org.ehcache.config.builders.CacheManagerBuilder; import org.ehcache.config.builders.ResourcePoolsBuilder; import org.ehcache.expiry.ExpiryPolicyBuilder;  import java.time.Duration; import java.time.Instant;  public class CustomOpaqueTokenIntrospector implements OpaqueTokenIntrospector {     private final OpaqueTokenIntrospector introspector;     private final CacheManager cacheManager;     private final Cache<String, OAuth2AuthenticatedPrincipal> AccessTokens;      public CustomOpaqueTokenIntrospector(String uri, String clientId, String clientSecret) {         cacheManager = CacheManagerBuilder.newCacheManagerBuilder().build(true);          accessTokens = cacheManager.createCache("iamCache",                 CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, OAuth2AuthenticatedPrincipal.class,                                 ResourcePoolsBuilder.heap(1000))                         .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(1800))));          this.introspector = new NimbusOpaqueTokenIntrospector(uri, clientId, clientSecret);     }      @Override     public OAuth2AuthenticatedPrincipal introspect(String token) {         if (this.accessTokens.containsKey(token)) {             OAuth2AuthenticatedPrincipal cachedPrincipal = this.accessTokens.get(token);             if (cachedPrincipal.getAttribute("exp") != null                     && ((Instant) cachedPrincipal.getAttribute("exp"))                     .isAfter(Instant.now())) {                 return cachedPrincipal;             }             this.accessTokens.remove(token);         }          OAuth2AuthenticatedPrincipal principal = introspector.introspect(token);         this.accessTokens.put(token, principal);          return principal;     }      public Cache<String, OAuth2AuthenticatedPrincipal> getAccessTokensCacheFromCacheManager() {         return cacheManager.getCache("iamCache", String.class, OAuth2AuthenticatedPrincipal.class);     } }

代码解释

  • CacheManager 和 Cache 的初始化:构造函数中,我们初始化了 CacheManager 和 Cache 对象。CacheManager 用于管理多个 Cache 实例,而 Cache 用于存储 Token 和对应的 OAuth2AuthenticatedPrincipal。
  • 缓存配置: CacheConfigurationBuilder 用于配置缓存的行为,例如:
    • ResourcePoolsBuilder.heap(1000): 设置内存缓存的最大条目数为 1000。
    • ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(1800)): 设置缓存的过期时间为 30 分钟 (1800 秒)。
  • introspect 方法: introspect 方法是 OpaqueTokenIntrospector 接口的核心方法,用于验证 Token 的有效性并返回 Token 的元数据。
    • 首先,检查缓存中是否存在该 Token。
    • 如果缓存中存在该 Token,并且 Token 的过期时间未到,则直接从缓存中返回 OAuth2AuthenticatedPrincipal。
    • 如果缓存中不存在该 Token,或者 Token 已经过期,则调用 NimbusOpaqueTokenIntrospector 从认证服务器获取 Token 的元数据,并将结果存储到缓存中。

注意事项

  • 缓存失效策略: 选择合适的缓存失效策略至关重要。这里使用了基于时间的失效策略,即 Token 在一定时间后过期。你也可以根据实际情况选择其他策略,例如基于大小的失效策略或基于访问频率的失效策略。
  • 缓存大小: 缓存的大小需要根据实际情况进行调整。如果缓存太小,则会导致频繁的缓存失效,从而降低性能。如果缓存太大,则会占用过多的内存资源。
  • 异常处理: 在实际应用中,需要考虑各种异常情况,例如认证服务器不可用、网络连接错误等。建议添加适当的异常处理逻辑,以保证系统的稳定性和可靠性。
  • 缓存同步:分布式系统中,需要考虑缓存同步的问题。可以使用分布式缓存解决方案,例如 redis 或 memcached,来保证各个节点上的缓存数据一致。

总结

通过自定义 OpaqueTokenIntrospector 并集成缓存机制,可以有效减少对认证服务器的依赖,提高系统在认证服务器不稳定时的可用性和性能。在实际应用中,需要根据具体情况选择合适的缓存失效策略、缓存大小和异常处理机制,以保证系统的稳定性和可靠性。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享