如何在ASP.NET Core中复现AAD B2C SecurityTokens的缓存刷新机制?
在ASP.NET Core中复现OpenIdConnectCachingSecurityTokenProvider的缓存刷新行为
当然可以!在ASP.NET Core里,虽然没有直接对应旧ASP.NET中OpenIdConnectCachingSecurityTokenProvider的现成组件,但我们可以通过自定义令牌验证逻辑结合缓存服务,轻松实现“缓存SecurityToken 1分钟后再刷新”的需求。下面是具体的实现方案:
核心思路
我们的目标是对验证过的令牌结果进行缓存,在1分钟内重复使用缓存结果,超过时间后重新执行令牌验证(相当于刷新缓存)。主要通过以下两步实现:
- 配置缓存服务(内存缓存或分布式缓存)
- 自定义JWT令牌处理器,在验证逻辑中加入缓存判断
具体实现步骤
1. 添加缓存服务
首先在Program.cs中注册缓存服务,这里先以内存缓存为例:
builder.Services.AddMemoryCache();
如果你的API是多实例部署,建议改用分布式缓存(比如Redis),只需要替换成对应的缓存注册代码即可,逻辑核心是一致的。
2. 自定义带缓存的令牌处理器
创建一个继承自JwtSecurityTokenHandler的自定义处理器,注入IMemoryCache来实现缓存逻辑:
public class CachingJwtSecurityTokenHandler : JwtSecurityTokenHandler { private readonly IMemoryCache _cache; // 设置缓存有效期为1分钟 private readonly TimeSpan _cacheExpiration = TimeSpan.FromMinutes(1); public CachingJwtSecurityTokenHandler(IMemoryCache cache) { _cache = cache ?? throw new ArgumentNullException(nameof(cache)); } public override ClaimsPrincipal ValidateToken(string token, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { // 用令牌哈希值作为缓存键,确保唯一性同时避免长字符串占用空间 var cacheKey = $"ValidatedToken_{token.GetHashCode()}"; // 先尝试从缓存获取已验证的结果 if (_cache.TryGetValue(cacheKey, out (ClaimsPrincipal Principal, SecurityToken Token) cachedResult)) { // 刷新缓存过期时间(滑动过期,活跃令牌不会过早失效) _cache.Set(cacheKey, cachedResult, _cacheExpiration); validatedToken = cachedResult.Token; return cachedResult.Principal; } // 缓存未命中,执行原生令牌验证 var principal = base.ValidateToken(token, validationParameters, out validatedToken); // 将验证结果存入缓存 _cache.Set(cacheKey, (principal, validatedToken), _cacheExpiration); return principal; } }
这里我们把ClaimsPrincipal和SecurityToken一起缓存,同时使用滑动过期策略——每次命中缓存时都会重新设置1分钟的过期时间,确保活跃的令牌不会过早过期。
3. 注册自定义处理器到认证服务
在Program.cs的认证配置中,替换默认的令牌验证器为我们自定义的缓存版本:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 配置你的OpenID Connect参数,比如身份提供者地址、受众等 options.Authority = "https://your-identity-provider.com"; options.Audience = "your-api-resource-audience"; // 清除默认的验证器,添加自定义的缓存处理器 options.SecurityTokenValidators.Clear(); options.SecurityTokenValidators.Add(new CachingJwtSecurityTokenHandler( builder.Services.BuildServiceProvider().GetRequiredService<IMemoryCache>())); });
额外说明
- 如果需要绝对过期(不管是否访问,1分钟后强制刷新),可以在设置缓存时使用
MemoryCacheEntryOptions指定AbsoluteExpirationRelativeToNow,替代滑动过期逻辑。 - 缓存键的生成方式可以根据实际需求调整,比如结合令牌的
exp字段,避免缓存已过期的令牌。 - 对于分布式场景,只需将内存缓存替换为Redis等分布式缓存服务,代码逻辑不需要大的改动。
内容的提问来源于stack exchange,提问作者NicoC
相关产品推荐
相关产品推荐

