ASP.NET Core托管身份调用下游API授权失败问题排查
解决Azure托管身份调用下游API授权失败的方案
1. 下游应用配置双身份验证方案
你的下游是混合UI+API的应用,必须同时支持OpenIdConnect(给UI登录用)和JwtBearer(给API令牌验证用),不能二选一。修改Program.cs:
var builder = WebApplication.CreateBuilder(args); // 先加OpenIdConnect,保障UI登录正常 builder.Services.AddAuthentication() .AddMicrosoftIdentityWebApp(builder.Configuration, "AzureAd") .EnableTokenAcquisitionToCallDownstreamApi() .AddInMemoryTokenCaches(); // 再加JwtBearer,专门处理API的令牌验证 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { builder.Configuration.Bind("AzureAd", options); // 令牌受众设为下游应用的ClientId options.TokenValidationParameters.ValidAudience = builder.Configuration["AzureAd:ClientId"]; // 兼容v1和v2版本的Issuer,避免令牌验证失败 options.TokenValidationParameters.ValidIssuers = new[] { $"https://sts.windows.net/{builder.Configuration["AzureAd:TenantId"]}/", $"https://login.microsoftonline.com/{builder.Configuration["AzureAd:TenantId"]}/v2.0" }; }); // 配置授权策略,分开UI和API的验证逻辑 builder.Services.AddAuthorization(options => { // UI用默认策略,走OpenIdConnect登录 options.DefaultPolicy = new AuthorizationPolicyBuilder() .AddAuthenticationSchemes(OpenIdConnectDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); // 新增API专属策略,走JwtBearer令牌验证 options.AddPolicy("ApiPolicy", policy => { policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser(); }); });
2. API控制器绑定专属授权策略
给需要托管身份访问的API控制器加上[Authorize(Policy = "ApiPolicy")],替换默认的[Authorize],这样API请求会用JwtBearer验证令牌,UI页面不受影响:
[ApiController] [Route("api/[controller]")] [Authorize(Policy = "ApiPolicy")] public class TestController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok("托管身份访问成功"); } }
3. 客户端正确获取目标令牌
客户端用DefaultAzureCredential获取令牌时,必须指定下游应用的Client ID作为受众,格式为api://{下游ClientId}/.default,确保令牌的aud字段和下游配置匹配:
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { // 如果你用的是用户分配的托管身份,这里指定它的ClientId ManagedIdentityClientId = "客户端托管身份ClientId" }); // 替换成下游应用的ClientId var scope = "api://xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx/.default"; var token = await credential.GetTokenAsync(new TokenRequestContext(new[] { scope })); // 调用API时带上Bearer令牌 var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Token); var response = await client.GetAsync("https://你的下游应用域名/api/test");
4. 检查Azure AD权限配置
- 下游应用要在Azure AD中暴露API,并给客户端托管身份(或本地Visual Studio登录账户)分配应用权限:选择
api://{下游ClientId}/.default权限,并且完成管理员同意。 - 本地测试时,VisualStudioCredential对应的账户需要有访问下游API的权限,或者下游应用允许该账户登录。
问题根源解释
- 只用OpenIdConnect的话,API请求的Bearer令牌会被忽略,因为OpenIdConnect是为浏览器跳转登录设计的,所以收到API请求时会直接重定向到登录页。
- 直接换成JwtBearer会破坏UI的登录流程,因为UI依赖OpenIdConnect的跳转逻辑。
内容的提问来源于stack exchange,提问作者Search4Sound
相关产品推荐
相关产品推荐

