IdentityServer4令牌本地存储及重启后过期令牌续期问题咨询
嘿,这个问题问到点子上了!先直接给你结论:如果用In-Memory存储搭建IdentityServer4,服务重启后,它无法识别之前颁发的令牌,也没法完成续期操作。
为什么会这样?
In-Memory存储的特点是所有数据都存在应用进程的内存里——包括客户端配置、资源定义,以及最重要的:颁发的刷新令牌记录、授权码等操作数据。一旦服务重启,这些内存里的数据会被完全清空。当旧令牌过期,你拿着之前获取的刷新令牌去请求续期时,IdentityServer根本找不到对应的刷新令牌记录,自然无法验证其有效性,更别说颁发新令牌了。
实现令牌续期的思路
要解决这个问题,核心是把IdentityServer的数据从内存迁移到持久化存储,再配合正确的配置和客户端逻辑,具体步骤如下:
1. 改用持久化存储(核心步骤)
IdentityServer4官方提供了Entity Framework Core的扩展包,支持将配置数据(客户端、身份资源、API资源)和操作数据(刷新令牌、授权码、撤销记录)存储到关系型数据库(比如SQL Server、MySQL、PostgreSQL等)。
示例代码(在Program.cs/Startup.cs中配置):
var connectionString = "你的数据库连接字符串"; services.AddIdentityServer() // 替换In-Memory配置为数据库存储 .AddConfigurationStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, opt => opt.MigrationsAssembly(typeof(Program).Assembly.FullName)); }) // 配置操作数据的持久化存储(存刷新令牌等) .AddOperationalStore(options => { options.ConfigureDbContext = b => b.UseSqlServer(connectionString, opt => opt.MigrationsAssembly(typeof(Program).Assembly.FullName)); // 开启自动清理过期的令牌/授权码数据 options.EnableTokenCleanup = true; options.TokenCleanupInterval = 3600; // 每小时清理一次 }) // 生产环境请使用持久化签名证书,不要用这个开发用的 .AddDeveloperSigningCredential();
配置完成后,需要通过EF迁移初始化数据库:
# 初始化配置存储迁移 dotnet ef migrations add InitialIdentityServerConfiguration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration # 初始化操作存储迁移 dotnet ef migrations add InitialIdentityServerOperational -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/Operational # 应用迁移到数据库 dotnet ef database update -c ConfigurationDbContext dotnet ef database update -c PersistedGrantDbContext
2. 配置客户端支持刷新令牌
确保你的客户端配置里开启了离线访问权限,允许使用刷新令牌:
new Client { ClientId = "your-web-app-client", ClientSecrets = { new Secret("your-client-secret".Sha256()) }, AllowedGrantTypes = GrantTypes.Code, RedirectUris = { "https://your-web-app.com/signin-oidc" }, PostLogoutRedirectUris = { "https://your-web-app.com/signout-callback-oidc" }, AllowedScopes = { "openid", "profile", "your-api-scope", "offline_access" // 必须添加这个scope才能获取刷新令牌 }, AllowOfflineAccess = true, // 开启离线访问,允许续期 // 可选:配置刷新令牌的过期策略 RefreshTokenExpiration = TokenExpiration.Sliding, SlidingRefreshTokenLifetime = 1296000, // 15天滑动过期 AbsoluteRefreshTokenLifetime = 2592000 // 30天绝对过期,防止无限续期 }
3. 客户端侧实现续期逻辑
当你的Web应用检测到访问令牌过期时,要主动使用刷新令牌向IdentityServer的/connect/token端点请求新的访问令牌。请求参数示例:
POST /connect/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded grant_type=refresh_token& refresh_token=你的刷新令牌& client_id=your-web-app-client& client_secret=your-client-secret& scope=openid profile your-api-scope
如果使用OIDC中间件(比如ASP.NET Core的OpenID Connect中间件),它会自动处理令牌续期逻辑,你只需要确保中间件配置正确即可。
4. 生产环境额外注意事项
- 签名证书:不要在生产环境使用
AddDeveloperSigningCredential,要使用持久化的签名证书(比如从文件、Azure Key Vault或其他密钥管理服务加载)。否则服务重启后签名密钥变更,之前颁发的令牌会无法验证。 - 令牌清理:确保
OperationalStore的自动清理功能开启,定期删除过期数据,避免数据库膨胀。
内容的提问来源于stack exchange,提问作者Francesco Calise

