如何在含Razor Pages与Web API的ASP.NET Core应用中实现AD B2C认证
ASP.NET Core混合Razor Pages+Web API的AD B2C安全实现方案
核心思路
要解决这个问题,关键是分离Web应用(Razor Pages)和Web API的认证管道:Razor Pages依赖Cookie认证实现用户登录,Web API依赖JWT Bearer认证验证请求令牌,不能只用单一的WebAppAuthentication配置。
一、AD B2C应用注册配置
- 在AD B2C中注册单个应用(也可分开注册,单应用更简便)
- 进入应用的「暴露API」页面,添加自定义范围(如
api://{你的应用Client ID}/access_as_user),设置范围名称和描述 - 进入「API权限」页面,添加刚才定义的自定义范围,并完成管理员同意(确保应用能获取该范围的令牌)
二、ASP.NET Core服务配置
1. 同时配置两种认证方案
在Program.cs中同时添加Cookie认证(供Razor Pages)和Bearer认证(供Web API),并指定不同的方案名称:
builder.Services.AddAuthentication() // Razor Pages用的Cookie认证方案,命名为"CookieAuth" .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"), "CookieAuth") // Web API用的Bearer认证方案,命名为"BearerAuth" .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"), "BearerAuth"); // 设置默认认证/挑战方案为Cookie(适配Razor Pages的登录流程) builder.Services.Configure<AuthenticationOptions>(options => { options.DefaultAuthenticateScheme = "CookieAuth"; options.DefaultChallengeScheme = "CookieAuth"; });
2. 定义API专属授权策略
创建仅接受Bearer令牌且包含指定范围声明的授权策略:
builder.Services.AddAuthorization(options => { options.AddPolicy("ApiAccessPolicy", policy => { policy.AuthenticationSchemes.Add("BearerAuth"); policy.RequireAuthenticatedUser(); // 验证令牌包含之前定义的API范围声明 policy.RequireClaim("scp", "access_as_user"); }); });
三、Razor Pages调用API的正确姿势
在Razor Pages的后台代码中,通过ITokenAcquisition获取针对API范围的AccessToken,并且确保请求仅携带Bearer令牌(不要混入Cookie):
private readonly IHttpClientFactory _httpClientFactory; private readonly ITokenAcquisition _tokenAcquisition; public IndexModel(IHttpClientFactory httpClientFactory, ITokenAcquisition tokenAcquisition) { _httpClientFactory = httpClientFactory; _tokenAcquisition = tokenAcquisition; } public async Task OnGetAsync() { var apiScope = "api://{你的应用Client ID}/access_as_user"; // 获取针对API范围的AccessToken var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { apiScope }); var client = _httpClientFactory.CreateClient(); // 手动添加Bearer令牌到请求头 client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); // 调用自身API var response = await client.GetAsync($"{Request.Scheme}://{Request.Host}/api/values"); response.EnsureSuccessStatusCode(); var apiContent = await response.Content.ReadAsStringAsync(); // 处理API返回内容 }
四、Web API端点授权
在API控制器(或API型Razor Pages)上应用之前定义的授权策略,确保只有携带有效Bearer令牌的请求能访问:
[ApiController] [Route("api/[controller]")] [Authorize(Policy = "ApiAccessPolicy")] public class ValuesController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok(new string[] { "value1", "value2" }); } }
常见问题排查
- 解析获取的AccessToken(用jwt.ms),确认包含
scp声明且值为定义的API范围 - 检查API端点的授权策略是否指定了
BearerAuth方案,避免默认使用Cookie认证导致跳转到登录页返回HTML - 确认AD B2C应用注册中已完成API范围的管理员同意,否则无法获取有效令牌
内容的提问来源于stack exchange,提问作者ANIKET JHA
相关产品推荐
相关产品推荐

