You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Identity Server 4客户端自定义声明缺失问题求助

解决Identity Server 4授权码+PKCE模式下自定义声明/范围声明缺失问题

以下是针对你遇到的声明缺失问题的具体解决步骤,按优先级排序:


1. 检查Identity Server的资源配置

首先要确保自定义声明已经关联到对应的身份资源(IdentityResource)或API资源(ApiResource),否则Identity Server不会把声明放入Token中。

配置自定义身份资源(用于身份相关声明)

在Identity Server的Config.cs中添加包含自定义声明的身份资源:

public static IEnumerable<IdentityResource> IdentityResources =>
    new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
        // 自定义身份资源,关联你的自定义声明
        new IdentityResource(
            name: "mycustomscope",
            displayName: "自定义权限范围",
            userClaims: new List<string> { "mycustomclaim" }
        )
    };

配置API资源(用于API访问相关声明)

如果声明是API专属的,需要在Config.cs中配置ApiResource:

public static IEnumerable<ApiResource> ApiResources =>
    new List<ApiResource>
    {
        new ApiResource("myapi", "我的业务API")
        {
            // 将自定义声明绑定到该API资源
            UserClaims = { "mycustomclaim" }
        }
    };

2. 确保MVC客户端请求了正确的Scope

在MVC客户端的Startup.cs中,修改OpenIdConnect配置,添加需要的Scope,确保客户端明确请求包含自定义声明的范围:

services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
    options.Authority = "https://你的IdentityServer地址";
    options.ClientId = "你的客户端ID";
    options.ResponseType = "code";
    options.UsePkce = true;
    options.SaveTokens = true;

    // 清除默认Scope,按需添加
    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("mycustomscope"); // 添加自定义范围
    options.Scope.Add("myapi"); // 如果是API资源范围,也要添加

    // 关键:映射自定义声明,避免被默认规则过滤
    options.ClaimActions.MapUniqueJsonKey("mycustomclaim", "mycustomclaim");
    // 开启从UserInfo端点获取声明(如果声明不在ID Token中)
    options.GetClaimsFromUserInfoEndpoint = true;
});

3. 自定义ProfileService确保声明被返回

默认的ProfileService可能不会自动将所有用户声明放入Token,需要自定义实现来主动添加需要的声明:

创建自定义ProfileService

public class CustomProfileService : IProfileService
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;

    public CustomProfileService(UserManager<ApplicationUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory)
    {
        _userManager = userManager;
        _claimsFactory = claimsFactory;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var userId = context.Subject.GetSubjectId();
        var user = await _userManager.FindByIdAsync(userId);
        if (user == null) throw new ArgumentException("用户不存在");

        // 获取用户基础声明
        var principal = await _claimsFactory.CreateAsync(user);
        var claims = principal.Claims.ToList();

        // 添加自定义声明(可从用户实体或其他数据源获取)
        claims.Add(new Claim("mycustomclaim", "mycustomclaim"));

        // 只返回客户端请求的声明(或全部,根据需求调整)
        context.IssuedClaims = claims.Where(c => 
            context.RequestedClaimTypes.Contains(c.Type) || 
            context.RequestedClaimTypes.Contains("*")
        );
    }

    public async Task IsActiveAsync(IsActiveContext context)
    {
        var userId = context.Subject.GetSubjectId();
        var user = await _userManager.FindByIdAsync(userId);
        context.IsActive = user != null;
    }
}

在Identity Server中注册自定义ProfileService

在Identity Server的Startup.cs中添加注册:

services.AddScoped<IProfileService, CustomProfileService>();

4. 验证授权策略配置

确保MVC客户端的授权策略配置正确,并且在Controller中正确应用:

// Startup.cs中添加授权策略
services.AddAuthorization(options =>
{
    options.AddPolicy("mypolicy", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireClaim("mycustomclaim", "mycustomclaim");
    });
});

// Controller中应用策略
[Authorize(Policy = "mypolicy")]
public IActionResult Index()
{
    var claims = User.Claims;
    foreach (var claim in claims)
    {
        _logger.LogDebug("{type}: {value}", claim.Type, claim.Value);
    }
    return View();
}

关键说明

  • PersistedGrants表中的声明只是授权数据的存储,不代表会自动传递到客户端,必须确保Identity Server在颁发Token时将声明包含进去。
  • 如果声明未出现在ID Token中,开启GetClaimsFromUserInfoEndpoint = true可以让客户端从UserInfo端点拉取完整声明。

内容的提问来源于stack exchange,提问作者Marvinatorrr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 18:19:52