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

如何在Asp.Net Core 2.0中用IdentityServer4混合流代用户调用API并解决名称为空问题

解决IdentityServer4 2.1.2 + ASP.NET Core 2.0中API无法获取User.Identity.Name的问题

这种情况我之前也碰到过,核心问题一般是access token里缺少name声明,或者API没有正确将token中的声明映射到User.Identity.Name。咱们一步步来排查解决:

1. 先确认Access Token里有没有name字段

这是最基础的一步,你可以把Web应用获取到的access token复制到jwt.io(本地解析就行,不用上传),查看Payload部分是否包含name键值对。如果没有,那问题出在IdentityServer的配置上;如果有,那就是API的认证配置没处理好。

2. 配置IdentityServer确保颁发的Token包含name声明

2.1 确保IdentityResources包含Profile资源

Profile资源默认包含name声明,在你的Config类里要加上:

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(), // 必须的OpenID资源
        new IdentityResources.Profile() // 包含name、family_name等声明
    };
}

2.2 配置API资源包含name声明

让API明确接收name这个用户声明:

public static IEnumerable<ApiResource> GetApiResources()
{
    return new List<ApiResource>
    {
        new ApiResource("api1", "My API")
        {
            UserClaims = { "name" } // 告诉IdentityServer要把name声明包含到access token里
        }
    };
}

2.3 客户端配置要请求正确的Scope

Web应用作为客户端,必须请求openid、profile以及你的API scope,不然IdentityServer不会颁发包含这些声明的token:

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        new Client
        {
            ClientId = "webapp",
            ClientName = "Web Application",
            AllowedGrantTypes = GrantTypes.AuthorizationCode,
            ClientSecrets = { new Secret("secret".Sha256()) },
            RedirectUris = { "https://localhost:5001/signin-oidc" },
            PostLogoutRedirectUris = { "https://localhost:5001/signout-callback-oidc" },
            AllowedScopes = {
                "openid",
                "profile",
                "api1" // 你的API scope
            },
            AllowOfflineAccess = true
        }
    };
}

3. 检查Web应用的认证配置

确保Web应用在获取token时请求了正确的scope,并且保存token以便调用API:

services.AddAuthentication(options =>
{
    options.DefaultScheme = "Cookies";
    options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
    options.Authority = "https://localhost:5000";
    options.ClientId = "webapp";
    options.ClientSecret = "secret";
    options.ResponseType = "code id_token";
    // 显式添加需要的scope
    options.Scope.Add("profile");
    options.Scope.Add("api1");
    options.Scope.Add("offline_access");
    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true; // 必须开启,这样才能拿到access token调用API
});

4. 配置API正确映射声明到User.Identity.Name

ASP.NET Core默认的NameClaimType是http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name,但IdentityServer颁发的token里用的是短名称name,所以需要在API的认证配置里手动映射:

services.AddAuthentication("Bearer")
    .AddIdentityServerAuthentication(options =>
    {
        options.Authority = "https://localhost:5000";
        options.RequireHttpsMetadata = false;
        options.ApiName = "api1";
        // 把token里的"name"声明映射到User.Identity.Name
        options.NameClaimType = "name";
    });

5. (可选)自定义ProfileService确保返回name声明

如果你的用户系统里name不是默认的UserName,或者需要自定义声明内容,可以实现IProfileService来控制返回的声明:

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

    public CustomProfileService(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }

    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        var user = await _userManager.GetUserAsync(context.Subject);
        if (user == null) return;
        
        // 添加name声明,这里可以换成用户的真实姓名等
        var claims = new List<Claim>
        {
            new Claim("name", user.UserName)
        };
        
        context.IssuedClaims.AddRange(claims);
    }

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

然后在Startup里注册这个服务:

services.AddTransient<IProfileService, CustomProfileService>();

最后验证

做完上面的步骤后,重新启动所有服务,获取新的access token,再去API里查看User.Identity.Name应该就能拿到正确的用户名了。如果还是不行,再用jwt.io检查token里的name字段是否存在,逐步排查每一步的配置有没有遗漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:38:22