IdentityServer4内存存储集成测试遇invalid_grant错误求助
我来帮你排查这个invalid_grant的问题,在IdentityServer4的密码模式测试场景里,这个错误通常由几个常见配置问题导致,咱们逐一分析解决:
1. TestUser的密码未正确哈希(最可能的根因)
IdentityServer4的TestUser类的Password属性要求存储哈希后的密码,而不是明文。默认的TestUserPasswordValidator会用ASP.NET Core的PasswordHasher来验证密码——如果你直接给Password赋值明文,验证时会把输入的密码哈希后和存储的明文对比,自然不匹配,就会返回invalid_username_or_password。
修复方法很简单,先生成哈希密码再赋值:
// 实例化密码哈希器 var passwordHasher = new PasswordHasher<TestUser>(); // 为测试用户生成哈希密码 var elevatedUser = MyDemoUser.ElevatedUser; var hashedElevatedPwd = passwordHasher.HashPassword(null, elevatedUser.Password); var workstationUser = MyDemoUser.WorkstationUser; var hashedWorkstationPwd = passwordHasher.HashPassword(null, workstationUser.Password); // 更新TestUser配置 builder.AddTestUsers(new List<TestUser> { new TestUser { SubjectId = Guid.NewGuid().ToString(), Claims = new List<Claim> { new Claim(JwtClaimTypes.Subject, elevatedUser.UserName), new Claim(JwtClaimTypes.Email, elevatedUser.Email), new Claim(JwtClaimTypes.Role, elevatedUser.Roles[0]), new Claim(JwtClaimTypes.Role, elevatedUser.Roles[1]) }, IsActive = true, Password = hashedElevatedPwd, // 用哈希后的密码 Username = elevatedUser.UserName }, new TestUser { SubjectId = Guid.NewGuid().ToString(), Claims = new List<Claim> { new Claim(JwtClaimTypes.Subject, workstationUser.UserName), new Claim(JwtClaimTypes.Email, workstationUser.Email), new Claim(JwtClaimTypes.Role, workstationUser.Roles[0]) }, IsActive = true, Password = hashedWorkstationPwd, Username = workstationUser.UserName } });
2. 客户端未启用密码授权类型
检查IS4Config.GetClients()返回的客户端配置,确保你的MyClient的AllowedGrantTypes包含GrantTypes.ResourceOwnerPassword:
// 示例客户端配置(参考调整你的代码) new Client { ClientId = MyClient.ClientId, ClientSecrets = { new Secret(MyClient.ClientSecret.Sha256()) }, AllowedGrantTypes = GrantTypes.ResourceOwnerPassword, // 必须包含这个授权类型 AllowedScopes = { MyApiResource.Gateway.Name }, // 其他必要配置... }
如果客户端没开启密码授权,IdentityServer会直接拒绝令牌请求,触发invalid_grant错误。
3. 发行者URI大小写不匹配
你在IdentityServer配置里设置的IssuerUri是"https://my.services.is4host"(小写m),但测试代码里调用GetDiscoveryDocumentAsync用的是"https://My.services.is4host"(大写M)。IdentityServer对发行者URI的验证是严格的,大小写不一致可能导致发现文档的issuer不匹配,进而影响令牌请求。建议统一成一致的大小写:
// 配置端保持统一 options.IssuerUri = "https://my.services.is4host"; // 测试端同步修改 var disco = await client.GetDiscoveryDocumentAsync("https://my.services.is4host");
4. 多余的SQLite内存数据库配置
你当前配置了SQLite内存库和SecurityDbContext,但并没有把IdentityServer的配置/操作数据绑定到这个DbContext(没有调用AddConfigurationStore或AddOperationalStore)。这个配置完全是多余的,建议移除,避免混淆和不必要的资源消耗。
按照以上步骤逐一排查,应该就能解决你的令牌请求错误了。
内容的提问来源于stack exchange,提问作者secretAgentB

