Identity Server 3调用userInfo接口无法返回声明问题排查
根据你提供的配置和问题描述,我帮你梳理几个关键排查点:
1. 确认标准Identity Scope的配置细节
你已经添加了StandardScopes.OpenId、StandardScopes.Profile、StandardScopes.Email、StandardScopes.Roles,但部分标准scope的默认配置可能没有明确指定要返回的claim,建议显式配置这些Identity类型的scope,确保返回规则清晰:
// 替换原有的StandardScopes实例为显式配置 new Scope { Name = Constants.StandardScopes.Profile, DisplayName = "User Profile", Type = ScopeType.Identity, Claims = new List<ScopeClaim> { new ScopeClaim(Constants.ClaimTypes.Name), new ScopeClaim(Constants.ClaimTypes.GivenName), new ScopeClaim(Constants.ClaimTypes.FamilyName) } }, new Scope { Name = Constants.StandardScopes.Email, DisplayName = "User Email", Type = ScopeType.Identity, Claims = new List<ScopeClaim> { new ScopeClaim(Constants.ClaimTypes.Email) } }, new Scope { Name = Constants.StandardScopes.Roles, DisplayName = "User Roles", Type = ScopeType.Identity, Claims = new List<ScopeClaim> { new ScopeClaim(Constants.ClaimTypes.Role) } }
2. 检查用户服务(IUserService)的ProfileData逻辑
/userInfo端点返回的内容完全依赖于IUserService中GetProfileDataAsync方法的实现,必须确保该方法根据请求的scope正确返回对应claim:
public Task GetProfileDataAsync(ProfileDataRequestContext context) { // 从你的用户存储中获取当前用户的所有claim var userClaims = FetchUserClaimsFromStore(context.Subject); // 根据请求的scope筛选需要返回的claim var requestedClaims = new List<Claim>(); if (context.RequestedScopes.Contains(Constants.StandardScopes.Profile)) { requestedClaims.AddRange(userClaims.Where(c => c.Type == Constants.ClaimTypes.Name || c.Type == Constants.ClaimTypes.GivenName || c.Type == Constants.ClaimTypes.FamilyName)); } if (context.RequestedScopes.Contains(Constants.StandardScopes.Email)) { requestedClaims.AddRange(userClaims.Where(c => c.Type == Constants.ClaimTypes.Email)); } if (context.RequestedScopes.Contains(Constants.StandardScopes.Roles)) { requestedClaims.AddRange(userClaims.Where(c => c.Type == Constants.ClaimTypes.Role)); } context.IssuedClaims = requestedClaims; return Task.FromResult(0); }
如果这个方法没有正确筛选返回对应claim,即使scope配置正确,/userInfo也不会返回预期内容。
3. 区分Identity Scope和Resource Scope的作用
你配置的api属于ScopeType.Resource,这类scope的claim只会嵌入到access_token中,用于Web API的权限验证,不会被/userInfo端点返回。所以你在api scope中定义的那些claim,不会出现在/userInfo的响应里,这是正常的设计逻辑。
4. 清理客户端配置的冗余项
你的客户端AllowedScopes里有重复项(比如Constants.StandardScopes.Roles和"roles"),虽然不会直接引发问题,但建议统一用常量引用,让配置更清晰:
AllowedScopes = new List<string> { Constants.StandardScopes.OpenId, Constants.StandardScopes.Profile, Constants.StandardScopes.Email, Constants.StandardScopes.Roles, "api" }
另外AllowAccessToAllScopes = true已经覆盖了AllowedScopes的限制,不过保留AllowedScopes能更直观地看到客户端可访问的范围。
5. 验证access_token的实际内容
建议用JWT解码工具(比如本地离线的JWT解析工具)解析你的access_token,确认:
- 除了scope列表,token中是否已经包含
name、email、role这些claim?
如果token本身就没有这些claim,那问题肯定出在用户服务或scope配置上,需要优先排查这部分。
按以上步骤逐一排查后,应该就能解决/userInfo端点不返回预期内容的问题。
内容的提问来源于stack exchange,提问作者JadedEric

