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

如何通过Azure认证为ASP.NET MVC与Web API添加自定义声明并实现角色授权

Azure Authentication下ASP.NET MVC与Web API的自定义声明及角色认证实现

一、核心需求拆解

你需要实现两个核心目标:

  • 让MVC应用获取的访问令牌包含自定义角色(如SomeRole),供API端做授权校验
  • 为MVC应用本身配置基于角色的身份认证逻辑

二、为访问令牌添加自定义角色声明

方式1:Azure AD静态配置应用角色(推荐,适合固定角色)

这是最标准的实现方式,角色声明会直接包含在Azure AD签发的访问令牌中:

  1. 登录Azure门户,找到你的API应用注册(对应api://123)
  2. 进入「应用角色」页面,点击「创建应用角色」,添加角色(名称填SomeRole,允许的成员类型选「用户/组」)
  3. 切换到你的MVC应用注册,进入「API权限」页面,点击「添加权限」→ 选择你的API → 勾选刚创建的SomeRole权限,最后点击「授予管理员同意」
  4. 完成后,用户登录MVC应用时,获取的访问令牌会自动包含roles声明,值为SomeRole

方式2:动态添加本地声明(适合业务逻辑驱动的动态角色)

如果角色需要根据业务逻辑动态生成,无法在Azure AD静态配置,可通过以下方式处理:

  • MVC端在用户登录时,通过OnTokenValidated事件将角色添加到本地认证主体(仅用于MVC自身的授权)
  • 调用API时,将自定义声明通过请求头传递给API(因为Azure AD签发的访问令牌无法客户端修改)

三、ASP.NET MVC端配置基于角色的身份认证

1. 修改Program.cs配置

更新认证服务,添加角色声明并启用授权:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
     .AddMicrosoftIdentityWebApp(options =>
     {
         builder.Configuration.Bind("AzureAd", options);
         options.ClientSecret = "89898";
         options.SaveTokens = true;
         options.Events ??= new OpenIdConnectEvents();
         
         // 登录后为用户添加自定义声明与角色
         options.Events.OnTokenValidated += async context =>
         {
             // 可替换为从数据库/业务服务获取用户角色的逻辑
             // var roleService = context.HttpContext.RequestServices.GetRequiredService<IRoleService>();
             // var userRoles = await roleService.GetRolesForUser(context.Principal.FindFirstValue(ClaimTypes.ObjectIdentifier));
             
             var customClaims = new List<Claim>
             {
                 new Claim(ClaimTypes.Role, "SomeRole"), // 添加角色声明
                 new Claim("Foo", "Bar") // 添加自定义声明
             };
             
             context.Principal.AddIdentity(new ClaimsIdentity(customClaims));
             // 更新认证票证,确保声明生效
             await context.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, context.Principal);
         };
     })
     .EnableTokenAcquisitionToCallDownstreamApi(new string[] { "api://123/.default" })
     .AddInMemoryTokenCaches();

// 添加授权服务,可自定义角色策略
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireSomeRole", policy => policy.RequireRole("SomeRole"));
});

// 启用中间件(顺序不能错)
app.UseAuthentication();
app.UseAuthorization();

2. 在MVC控制器中使用角色授权

在需要保护的Action或Controller上添加[Authorize]特性:

// 直接指定角色
[Authorize(Roles = "SomeRole")]
public IActionResult AdminDashboard()
{
    return View();
}

// 或者使用自定义策略
[Authorize(Policy = "RequireSomeRole")]
public IActionResult ProtectedAction()
{
    return View();
}

四、ASP.NET Web API端处理自定义声明与授权

情况1:使用Azure AD配置的应用角色

  1. 修改Program.cs,启用授权服务:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
    builder.Configuration.Bind("AzureAd", options);
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidIssuer = $"https://sts.windows.net/{builder.Configuration["AzureAd:TenantId"]}/",
        ValidateAudience = true,
        ValidAudience = "api://123",
        ValidateLifetime = true,
        ClockSkew = TimeSpan.FromMinutes(5)
    };
});

// 添加授权策略
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("RequireSomeRole", policy => policy.RequireRole("SomeRole"));
});

// 启用中间件
app.UseAuthentication();
app.UseAuthorization();
  1. 在API控制器中使用授权并获取声明:
[Authorize(Roles = "SomeRole")]
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    [HttpGet]
    public IActionResult GetData()
    {
        // 从令牌中获取角色与自定义声明
        var someRole = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role && c.Value == "SomeRole")?.Value;
        var fooClaim = User.Claims.FirstOrDefault(c => c.Type == "Foo")?.Value;
        
        return Ok(new { Message = "授权成功", Role = someRole, CustomClaim = fooClaim });
    }
}

情况2:使用动态传递的自定义声明

如果自定义声明是MVC端动态生成的,未包含在访问令牌中,需通过请求头传递:

  1. MVC端调用API时添加请求头:
private readonly ITokenAcquisition _tokenAcquisition;
private readonly IHttpClientFactory _httpClientFactory;

public YourMvcController(ITokenAcquisition tokenAcquisition, IHttpClientFactory httpClientFactory)
{
    _tokenAcquisition = tokenAcquisition;
    _httpClientFactory = httpClientFactory;
}

public async Task<IActionResult> CallApi()
{
    var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "api://123/.default" });
    var client = _httpClientFactory.CreateClient();
    
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    // 传递自定义声明到API
    var fooClaim = User.Claims.FirstOrDefault(c => c.Type == "Foo");
    if (fooClaim != null)
    {
        client.DefaultRequestHeaders.Add("X-Foo-Claim", fooClaim.Value);
    }
    
    var response = await client.GetAsync("https://your-api-url/api/data");
    var data = await response.Content.ReadFromJsonAsync<YourDataModel>();
    
    return View(data);
}
  1. API端从请求头获取声明:
[HttpGet]
public IActionResult GetData()
{
    var fooValue = Request.Headers["X-Foo-Claim"].FirstOrDefault();
    return Ok(new { Message = "授权成功", CustomClaimValue = fooValue });
}

五、关键注意事项

  • Azure AD签发的访问令牌不可客户端修改,所有需在令牌中体现的声明必须通过Azure AD配置(应用角色、用户扩展属性等)
  • MVC端OnTokenValidated事件添加的声明仅存在于本地Cookie认证票证,不会自动同步到访问令牌
  • API端默认会自动解析Azure AD的角色声明,无需额外配置RoleClaimType(Microsoft Identity Web已默认适配)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:05:03