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

ASP.NET Core OIDC客户端如何将given_name存入Claims?

问题描述

我有一个ASP.NET Core应用,使用以下配置实现OpenIdConnect认证:

builder.Services.AddAuthentication()
    .AddOpenIdConnect(
        "oidc",
        o =>
        {
            builder.Configuration.GetSection("Identity").Bind(o);
            o.ClientId = "webui";
            o.ClientSecret = "****";
            o.CallbackPath = "/cb_openIdConnect";
            o.SaveTokens = true;
            o.ResponseType = OpenIdConnectResponseType.Code;
            o.GetClaimsFromUserInfoEndpoint = true;
            o.Scope.Add("email");
            o.Scope.Add("profile");
            o.UsePkce = true;
            o.ClaimActions.MapUniqueJsonKey("given_name", "given_name");
        });

我的IDP服务器是自行管控的OpenIddict服务器。尽管已启用GetClaimsFromUserInfoEndpoint选项,但无法将UserInfo端点返回的Claims持久化到本地令牌中。

添加OnUserInformationReceived事件后,可以看到userinfo中返回了given_name:

o.Events.OnUserInformationReceived = e =>
{
    Console.WriteLine(e.User.ToString());
    return Task.CompletedTask;
};

输出内容:

{ "sub": "****", "given_name": "***", "family_name": "****" }

但通过AuthenticationStateProvider获取的UserPrincipal的Claims中找不到given_name。我尝试在事件中手动添加测试值,同样无法在页面的Claims列表中显示:

o.Events.OnUserInformationReceived = e =>
{
    e.Principal?.AddClaim("given_name", "wef");
    return Task.CompletedTask;
};

无论如何尝试,Claims始终只包含以下类型:

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
AspNet.Identity.SecurityStamp

如何将OIDC UserInfo端点的Claims存入HttpContext的UserPrincipal中,以便在网页上显示?


解决方案

1. 修正Claims映射规则

你已添加的MapUniqueJsonKey可以调整为使用标准Claim类型Uri,避免名称不匹配问题:

// 替换原有映射代码
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.GivenName, "given_name");
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.Surname, "family_name");

2. 配置Cookie认证保留自定义Claims

默认Cookie认证中间件会过滤部分Claims,需要显式配置保留所需字段:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie(options =>
{
    options.Cookie.Name = "WebUICookie";
    options.Events.OnSigningIn = context =>
    {
        // 确保UserInfo返回的Claims被添加到Cookie身份中
        var givenName = context.Principal.FindFirst("given_name") ?? context.Principal.FindFirst(ClaimTypes.GivenName);
        var familyName = context.Principal.FindFirst("family_name") ?? context.Principal.FindFirst(ClaimTypes.Surname);
        
        if (givenName != null && !context.Principal.Claims.Any(c => c.Type == ClaimTypes.GivenName))
        {
            context.Principal.Identities.First().AddClaim(givenName);
        }
        if (familyName != null && !context.Principal.Claims.Any(c => c.Type == ClaimTypes.Surname))
        {
            context.Principal.Identities.First().AddClaim(familyName);
        }
        return Task.CompletedTask;
    };
})
.AddOpenIdConnect("oidc", o =>
{
    // 原有配置保留,替换映射规则
    builder.Configuration.GetSection("Identity").Bind(o);
    o.ClientId = "webui";
    o.ClientSecret = "****";
    o.CallbackPath = "/cb_openIdConnect";
    o.SaveTokens = true;
    o.ResponseType = OpenIdConnectResponseType.Code;
    o.GetClaimsFromUserInfoEndpoint = true;
    o.Scope.Add("email");
    o.Scope.Add("profile");
    o.UsePkce = true;
    
    o.ClaimActions.MapUniqueJsonKey(ClaimTypes.GivenName, "given_name");
    o.ClaimActions.MapUniqueJsonKey(ClaimTypes.Surname, "family_name");
});

3. 禁用默认Claims过滤

如果仍有问题,可以清空默认的ClaimActions,只保留自己需要的映射:

o.ClaimActions.Clear();
// 手动映射所有需要的Claims
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.NameIdentifier, "sub");
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.Name, "name");
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.Email, "email");
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.GivenName, "given_name");
o.ClaimActions.MapUniqueJsonKey(ClaimTypes.Surname, "family_name");

4. 检查OpenIddict服务器配置

确认OpenIddict服务器的客户端webui已授权profile作用域,且UserInfo端点确实返回了given_name和family_name字段(可通过Postman直接调用UserInfo接口验证)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 05:13:21