Azure B2C中UI Web应用无法向API Web应用传递范围的问题
我之前也碰到过一模一样的情况,Easy Auth默认配置有时候确实不会自动带上你需要的API范围,咱们一步步来排查和解决:
检查UI应用Easy Auth的登录参数配置
你得确保在UI应用的App Service身份验证设置里,手动添加包含API范围的登录参数。具体操作是:进入Azure门户的UI应用→「身份验证」面板→编辑Azure AD B2C身份提供者→在「登录参数」里添加:scope=openid offline_access https://yourtenant.onmicrosoft.com/api/your_target_scope这里要注意,
openid和offline_access是必带的(前者用于获取ID Token,后者用于刷新令牌),后面的API范围要和你在API应用注册里定义的完全一致,包括完整的标识符(比如https://{tenant}.onmicrosoft.com/{api-app-id-uri}/{scope}),拼写错一个字符都不行。确认API范围发布与UI权限授予
先去Azure AD B2C的应用注册里找你的API应用,检查「公开API」部分的范围是否正确发布,范围名称和标识符有没有拼写错误;再切换到UI应用的「API权限」页面,确认已经添加了目标API的对应范围,并且点击了「授予管理员同意」——这步很关键,如果没做,用户登录时系统不会请求这些范围。验证API的JwtBearer中间件配置
如果你的API是.NET应用,在Program.cs(.NET6+)或Startup.cs里,要确保JwtBearer配置不仅指定了正确的受众,还开启了范围验证:builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/your_policy/v2.0/"; options.Audience = "https://yourtenant.onmicrosoft.com/api"; // 你的API应用ID URI options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, RoleClaimType = "roles", NameClaimType = "name" }; }); // 还要添加范围验证策略 builder.Services.AddAuthorization(options => { options.AddPolicy("RequireApiScope", policy => policy.RequireClaim("scp", "your_target_scope")); });然后在需要验证范围的控制器或方法上加上
[Authorize(Policy = "RequireApiScope")],这里的scp是Azure B2C返回的范围声明的固定键,别写错了。检查实际返回的令牌内容
用浏览器F12开发者工具,登录成功后查看本地存储的access_token,复制到jwt.io解码,看看scp声明里有没有你需要的范围。如果没有,说明UI的登录请求没带对参数,回到第一步重新检查;如果令牌里有范围但API还是不认,就去核对JwtBearer的受众和策略里的范围名称是否完全匹配。SPA场景可考虑用MSAL.js手动控制
如果你的UI是单页应用,Easy Auth的默认配置可能不够灵活,这时候可以用MSAL.js手动发起登录请求,明确指定需要的范围:const msalInstance = new msal.PublicClientApplication({ auth: { clientId: "your-ui-client-id", authority: "https://yourtenant.b2clogin.com/yourtenant.onmicrosoft.com/your_policy", redirectUri: "https://your-ui-app.azurewebsites.net" } }); async function loginAndGetToken() { const loginRequest = { scopes: ["openid", "offline_access", "https://yourtenant.onmicrosoft.com/api/your_target_scope"] }; const loginResponse = await msalInstance.loginPopup(loginRequest); const tokenRequest = { scopes: ["https://yourtenant.onmicrosoft.com/api/your_target_scope"], account: loginResponse.account }; const tokenResponse = await msalInstance.acquireTokenSilent(tokenRequest); // 用tokenResponse.accessToken调用API即可 }这种方式能更精准地控制请求的范围,避开Easy Auth默认配置的限制。
内容的提问来源于stack exchange,提问作者Jussi Palo

