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

.NET Core 2.2 Azure AD身份验证正常但角色授权返回访问拒绝

解决.NET Core 2.2中Azure AD角色授权跳转到AccessDenied的问题

首先咱们先解决你最开始遇到的No authenticationScheme was specified, and there was no DefaultChallengeScheme found报错——这个问题是因为新建项目的默认代码没有明确指定认证方案导致的,咱们先把基础配置捋顺:

第一步:修复基础认证配置

在Startup.cs的ConfigureServices方法里,明确将Azure AD认证设为默认方案,这样就能解决初始报错:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    // 指定Azure AD为默认认证/挑战方案
    services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        .AddAzureAD(options => Configuration.Bind("AzureAd", options));

    // 后续授权配置...
}

第二步:核心问题——角色/组的Claim映射

你遇到的[Authorize(Roles="xxx")]总是跳转到AccessDenied的核心原因是:Azure AD返回的角色/组信息没有被正确映射到.NET授权系统识别的ClaimTypes.Role类型上。咱们分两种场景处理:

场景1:使用Azure AD应用角色(App Roles)

如果是用Azure AD里创建的应用角色,需要在OpenIdConnect的token验证事件中,把token里的roles Claim转换成.NET的角色Claim:

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = context =>
        {
            // 从Azure AD返回的token中取出应用角色
            var appRoles = context.Principal.FindAll("roles").Select(c => c.Value);
            var identity = context.Principal.Identity as ClaimsIdentity;
            
            if (identity != null)
            {
                // 将应用角色添加到.NET的Role Claim类型中
                foreach (var role in appRoles)
                {
                    identity.AddClaim(new Claim(ClaimTypes.Role, role));
                }
            }

            return Task.CompletedTask;
        }
    };
});

同时要确保在Azure Portal里:

  • 你的应用注册中已经创建了对应的应用角色
  • 这些角色已经分配给了目标用户或安全组
  • 用户登录后的token里能通过jwt.ms工具看到roles Claim存在

场景2:使用Azure AD安全组

如果是用AD组(比如你提到的"Domain Users"),需要额外处理:

  1. 在Azure Portal的应用注册中,添加Microsoft Graph的Directory.Read.All应用权限并授予管理员同意
  2. 在应用注册的清单里,设置groupMembershipClaims为SecurityGroup或All,让Azure AD在token中返回用户所属组的ID
  3. 在代码中把组ID(或通过Graph API获取的组名称)映射为Role Claim:
options.Events = new OpenIdConnectEvents
{
    OnTokenValidated = async context =>
    {
        var identity = context.Principal.Identity as ClaimsIdentity;
        if (identity != null)
        {
            // 取出token中的组ID
            var groupIds = context.Principal.FindAll("groups").Select(c => c.Value);
            
            // 可选:调用Graph API根据组ID获取组名称(需要提前配置Graph API权限)
            // var graphClient = new GraphServiceClient(/* 认证信息 */);
            // foreach (var id in groupIds)
            // {
            //     var group = await graphClient.Groups[id].Request().GetAsync();
            //     identity.AddClaim(new Claim(ClaimTypes.Role, group.DisplayName));
            // }
            
            // 直接用组ID作为角色值(此时[Authorize(Roles="组ID")])
            foreach (var id in groupIds)
            {
                identity.AddClaim(new Claim(ClaimTypes.Role, id));
            }
        }
        return Task.CompletedTask;
    }
};

第三步:验证与调试

  1. 用jwt.ms解析用户登录后的token,确认里面存在对应的roles或groups Claim
  2. 确保[Authorize(Roles="xxx")]中的xxx与token里的Claim值完全一致(注意大小写敏感)
  3. 可以在控制器里注入ClaimsPrincipal,打印当前用户的所有Claim,确认角色Claim已正确添加

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 06:23:17