如何在Azure函数中清理OpenIddict过期无效的令牌与授权?
OpenIddict过期令牌/授权清理的Azure函数实现方案
一、核心清理逻辑
- 针对
OpenIddictTokens表:清理过期令牌(ExpirationDate小于当前UTC时间)、无效令牌(Status为Revoked或Invalidated) - 针对
OpenIddictAuthorizations表:清理自身状态为Revoked/Invalidated的授权,以及关联的令牌已全部失效的授权
二、Azure函数定时触发配置
用Timer触发器设置执行频率,比如每天凌晨2点执行(Cron表达式可按需调整):
[FunctionName("OpenIddictCleanupFunction")] public async Task Run([TimerTrigger("0 0 2 * * *")] TimerInfo myTimer, ILogger log, IServiceProvider serviceProvider) { // 清理逻辑调用 }
注:Cron表达式0 0 2 * * *表示UTC时间每天2点执行,若要适配本地时区,可在Azure函数配置中设置时区。
三、基于OpenIddict API的具体实现(EF Core场景)
通过OpenIddict内置的存储API操作,避免直接写裸SQL,兼容性更好:
1. 清理服务实现
using OpenIddict.Core; using OpenIddict.EntityFrameworkCore.Models; using Microsoft.EntityFrameworkCore; public class OpenIddictCleanupService { private readonly IOpenIddictTokenManager<OpenIddictEntityFrameworkCoreToken> _tokenManager; private readonly IOpenIddictAuthorizationManager<OpenIddictEntityFrameworkCoreAuthorization> _authorizationManager; private readonly ILogger<OpenIddictCleanupService> _logger; private const int _batchSize = 1000; public OpenIddictCleanupService( IOpenIddictTokenManager<OpenIddictEntityFrameworkCoreToken> tokenManager, IOpenIddictAuthorizationManager<OpenIddictEntityFrameworkCoreAuthorization> authorizationManager, ILogger<OpenIddictCleanupService> logger) { _tokenManager = tokenManager; _authorizationManager = authorizationManager; _logger = logger; } public async Task CleanupExpiredAndInvalidEntitiesAsync() { var now = DateTimeOffset.UtcNow; await CleanupTokensAsync(now); await CleanupAuthorizationsAsync(now); } private async Task CleanupTokensAsync(DateTimeOffset now) { int page = 0; while (true) { // 分段加载待删除令牌,避免内存溢出 var tokens = await _tokenManager.ListAsync( token => token.ExpirationDate <= now || token.Status is OpenIddictConstants.Statuses.Revoked or OpenIddictConstants.Statuses.Invalidated, query => query.Skip(page * _batchSize).Take(_batchSize) ).ToListAsync(); if (!tokens.Any()) break; foreach (var token in tokens) { try { await _tokenManager.DeleteAsync(token); _logger.LogInformation("已删除无效令牌: {TokenId}", token.Id); } catch (Exception ex) { _logger.LogError(ex, "删除令牌 {TokenId} 失败", token.Id); } } page++; } } private async Task CleanupAuthorizationsAsync(DateTimeOffset now) { int page = 0; while (true) { // 筛选自身无效或无有效令牌的授权 var authorizations = await _authorizationManager.ListAsync( auth => auth.Status is OpenIddictConstants.Statuses.Revoked or OpenIddictConstants.Statuses.Invalidated || !auth.Tokens.Any(token => token.ExpirationDate > now && token.Status == OpenIddictConstants.Statuses.Valid), query => query.Skip(page * _batchSize).Take(_batchSize) ).ToListAsync(); if (!authorizations.Any()) break; foreach (var auth in authorizations) { try { await _authorizationManager.DeleteAsync(auth); _logger.LogInformation("已删除无效授权: {AuthId}", auth.Id); } catch (Exception ex) { _logger.LogError(ex, "删除授权 {AuthId} 失败", auth.Id); } } page++; } } }
2. Azure函数中调用清理服务
[FunctionName("OpenIddictCleanupFunction")] public async Task Run([TimerTrigger("0 0 2 * * *")] TimerInfo myTimer, ILogger log, IServiceProvider serviceProvider) { using var scope = serviceProvider.CreateScope(); var cleanupService = scope.ServiceProvider.GetRequiredService<OpenIddictCleanupService>(); log.LogInformation("开始执行OpenIddict清理任务"); await cleanupService.CleanupExpiredAndInvalidEntitiesAsync(); log.LogInformation("OpenIddict清理任务执行完成"); }
四、Azure环境适配优化点
- 数据库索引优化:在
OpenIddictTokens表的ExpirationDate、Status字段,OpenIddictAuthorizations表的Status字段创建索引,避免全表扫描拖慢查询速度。 - 连接配置:Azure函数的数据库连接字符串统一用应用服务配置(Application Settings)管理,同时调整连接超时时间(建议设为300秒),适配大数据量删除操作。
- 监控告警:通过Azure Monitor收集清理日志,配置失败告警规则,及时发现异常。
- 事务控制:大数据量清理时建议不要用全局事务,分批次独立删除,减少数据库锁表风险。
内容的提问来源于stack exchange,提问作者Ali Khan
相关产品推荐
相关产品推荐

