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

ASP.NET Core中ClaimActions.MapJsonKey无法覆盖声明的问题

解决方案

问题根源

  1. 默认Claim映射覆盖自定义设置:AddMicrosoftAccount默认内置了ClaimTypes.Name和ClaimTypes.Email的映射规则,会优先使用Graph API返回的name(姓名)和userPrincipalName(可能带#EXT#的租户格式邮箱),导致你的自定义MapJsonKey不生效。
  2. 用户信息来源优先级:默认认证流程会调用Microsoft Graph的/me接口获取用户信息,而非直接解析AccessToken的JWT声明。

修复步骤

1. 清除默认Claim映射

先移除默认的Name和Email映射规则,避免覆盖自定义配置:

msOptions.ClaimActions.Remove(ClaimTypes.Name);
msOptions.ClaimActions.Remove(ClaimTypes.Email);
// 若需要完全重置所有默认映射,可使用:msOptions.ClaimActions.Clear();

2. 添加必要的权限范围

确保请求的权限包含获取邮箱所需的email或User.Read(后者会返回完整用户信息,包括mail字段):

msOptions.Scope.Add("User.Read");
msOptions.Scope.Add("email");

3. 配置自定义Claim映射

根据你需要的数据源选择对应配置:

方式一:从Graph API返回的用户信息中映射(推荐)

Graph API的/me接口返回的mail字段是用户的实际邮箱(无#EXT#),直接映射到对应的Claim类型:

msOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "mail");
msOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "mail");

方式二:直接从AccessToken的JWT声明中映射

如果不想调用Graph API,可关闭用户信息获取,直接使用AccessToken中的email声明:

// 关闭自动调用Graph API获取用户信息
msOptions.FetchUserDetails = false;
// 映射AccessToken中的email声明
msOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "email");
msOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "email");

4. 简化OnCreatingTicket事件(可选)

如果选择方式一,可完全移除手动修改Claim的冗余代码;若仍需自定义处理,可简化为:

msOptions.Events = new OAuthEvents
{
    OnCreatingTicket = context =>
    {
        var email = context.User.GetString("mail");
        context.Identity.AddClaim(new Claim(ClaimTypes.Name, email));
        return Task.CompletedTask;
    }
};

修改后的完整代码示例

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = MicrosoftAccountDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
    options.LoginPath = "/signin-microsoft";
})
.AddMicrosoftAccount(msOptions =>
{
    msOptions.ClientId = builder.Configuration.GetValue<string>("MicrosoftAuthConfig:ClientId");
    msOptions.ClientSecret = builder.Configuration.GetValue<string>("MicrosoftAuthConfig:ClientSecret");
    msOptions.AuthorizationEndpoint = builder.Configuration.GetValue<string>("MicrosoftAuthConfig:AuthorizationEndpoint");
    msOptions.TokenEndpoint = builder.Configuration.GetValue<string>("MicrosoftAuthConfig:TokenEndpoint");

    // 清除默认的Name和Email映射
    msOptions.ClaimActions.Remove(ClaimTypes.Name);
    msOptions.ClaimActions.Remove(ClaimTypes.Email);

    // 添加必要的权限范围
    msOptions.Scope.Add("User.Read");
    msOptions.Scope.Add("email");

    // 自定义Claim映射(从Graph API的mail字段获取)
    msOptions.ClaimActions.MapJsonKey(ClaimTypes.Name, "mail");
    msOptions.ClaimActions.MapJsonKey(ClaimTypes.Email, "mail");

    // 保留需要的事件处理
    msOptions.Events = new OAuthEvents
    {
        OnRedirectToAuthorizationEndpoint = context =>
        {
            Console.WriteLine($"Redirecting to: {context.RedirectUri}");
            context.Response.Redirect(context.RedirectUri);
            return Task.CompletedTask;
        }
    };
});

关键说明

  • 若用户是外部账户(如个人微软账户登录企业租户),userPrincipalName会包含#EXT#,而mail字段才是用户的真实邮箱,因此优先映射mail字段。
  • 确保Azure AD应用注册中已配置正确的权限(User.Read和email),并授予管理员同意(若为租户应用)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:32:29