IdentityServer4负载均衡故障排查:是否因未持久化刷新令牌?
排查IdentityServer4多实例负载均衡失效与OperationalStore无数据问题
首先,你遇到的负载均衡失效问题确实和未持久化授权数据直接相关——全内存存储时,授权码、刷新令牌等数据只存在单个实例的内存中,多实例请求分发到不同节点时,后续请求(比如刷新令牌)找不到对应数据就会失败。接下来针对你的代码和问题逐一排查:
1. 自定义IPersistedGrantStore与官方AddOperationalStore冲突
你的代码中同时做了两件冲突的事:
- 调用
identityServerBuilder.AddOperationalStore(...):这会自动注册官方基于数据库的IPersistedGrantStore实现(类名恰好也是PersistedGrantStore) - 手动注册
services.AddTransient<IPersistedGrantStore, PersistedGrantStore>():这会直接覆盖官方的数据库实现
如果你的自定义PersistedGrantStore没有正确使用PersistedGrantDbContext读写数据库,自然不会有数据存入DB。解决方法:
- 删除手动注册
IPersistedGrantStore的代码,让AddOperationalStore提供的默认实现生效 - 若确实需要自定义持久化逻辑,确保你的
PersistedGrantStore正确注入PersistedGrantDbContext并实现完整的CRUD方法
2. 验证AddOperationalStore配置与数据库迁移
确认以下细节:
- 检查
dbSettings.ConnectionString是否正确指向PostgreSQL,数据库用户具备读写权限 - 查看应用启动日志,确认
PersistedGrantDbContext.Database.Migrate()是否成功执行,有没有抛出连接失败、迁移脚本缺失等异常 - 确认
migrationsAssembly是否正确获取到包含迁移文件的程序集(你的代码中this.GetType().Assembly.GetName().Name是正确的,只要迁移文件在当前项目中)
3. 确认客户端配置允许离线访问
只有当客户端配置中AllowOfflineAccess = true,且请求令牌时携带offline_access scope,IdentityServer才会生成刷新令牌并持久化到数据库。检查你的JsonFileClientStore中的客户端配置,确保需要刷新令牌的客户端开启了这个配置。
4. 验证负载均衡环境的PublicOrigin配置
你的代码中设置了iso.PublicOrigin = applicationSettings.PublicOriginUri,这在负载均衡场景下至关重要——务必确保这个地址是负载均衡器的公网入口地址,否则IdentityServer生成的令牌中的回调地址、issuer会和实际请求不匹配,导致验证失败。
修复后的关键代码示例
移除自定义的IPersistedGrantStore注册后,ConfigureServices中相关部分应如下:
var identityServerBuilder = services .AddIdentityServer(iso => { if (!String.IsNullOrEmpty(applicationSettings.PublicOriginUri)) iso.PublicOrigin = applicationSettings.PublicOriginUri; // 其他IdentityServer配置... }); // 签名凭证配置(开发/生产环境逻辑)... // 启用数据库存储操作数据(授权码、令牌、同意信息) identityServerBuilder.AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseNpgsql(dbSettings.ConnectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); options.EnableTokenCleanup = true; options.TokenCleanupInterval = 10; // 测试用短间隔,生产建议调长 }); // 移除这行冲突代码:services.AddTransient<IPersistedGrantStore, PersistedGrantStore>(); // 其他服务注册...
测试验证步骤
- 启动单个实例,发起授权请求并获取刷新令牌
- 查看PostgreSQL的
persisted_grants表,确认是否有数据存入 - 启动第二个实例,用同一个刷新令牌请求新的访问令牌
- 若能成功获取令牌,说明多实例间的数据共享正常,负载均衡问题解决
内容的提问来源于stack exchange,提问作者user2082630
相关产品推荐
相关产品推荐

