Microsoft Identity Web API中间件拒绝验证访问令牌问题排查
我在ASP.NET Core Web API的认证环节遇到问题:使用React + Fable构建的SPA客户端,通过Msal可正常获取访问令牌,并将其放在Authorization头中发送给Web API。当前SPA前端部署在Vite开发服务器上,通过该服务器代理前端到后端的请求。
问题1
既然已经从Azure AD获取到令牌,是否可以认为客户端侧没有问题?
问题2
以下是我的appsettings.json内容:
"AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "simple-login-page.com", "TenantId": "ec88369d-6c2f-4f15-b0c7-adbe35caec77", "ClientId": "fd12b58b-6c39-4f86-ba02-98e6d7ee5eb5", "CallbackPath": "/signin-oidc" },
我是否遗漏了什么配置?已验证其中的ID与客户端侧的一致。
问题3
以下是我的服务器端Program.cs代码(F#):
[<EntryPoint>] let main _ = let builder = WebApplication.CreateBuilder(WebApplicationOptions( WebRootPath = "public" )) builder.Services .AddGiraffe() .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection "AzureAd") |> ignore let app = builder.Build() app .UseAuthentication() .Use(Func<HttpContext,RequestDelegate,Task>(fun ctx next -> task { if ctx.User.Identity.IsAuthenticated then return! next.Invoke(ctx) else return! ctx.ForbidAsync() })) .UseFileServer() .UseGiraffe(webApp) app.Run() 0 // Exit code
每当服务器收到请求时,都会提示某个密钥验证失败。我是否遗漏了配置?是否需要在Azure AD中进行额外配置以允许服务器使用它?
解答
问题1
不能直接认定客户端无问题。虽然能获取令牌,但需验证以下核心信息:
- 令牌的**受众(Audience)**是否匹配Web API的客户端ID;
- 签名算法是否为Azure AD默认的RS256;
- 令牌是否在有效期内;
- 请求的Authorization头格式是否为
Bearer <token>(注意空格不能少)。
可以使用JWT解析工具检查令牌内容,确认上述字段是否符合要求。
问题2
你的配置缺少关键的Audience字段,这是密钥验证失败的常见诱因。需在AzureAd节点中添加:
"Audience": "api://fd12b58b-6c39-4f86-ba02-98e6d7ee5eb5"
格式为api://{你的API客户端ID},其中客户端ID就是配置中已有的ClientId值。另外,CallbackPath用于OIDC登录回调,Web API无需该配置,可直接移除以避免混淆。
问题3
除了补全配置,还需检查以下几点:
Azure AD API应用注册配置:
- 进入API的应用注册页面,在「身份验证」→「高级设置」中确认已启用ID令牌和访问令牌;
- 在「公开API」页面添加正确的权限范围,并确保SPA客户端已被授予该范围的权限(需管理员或用户同意,取决于权限类型);
- 确认「证书和密码」中配置的密钥有效,或者允许使用Azure AD公钥进行签名验证(默认启用,但自定义密钥需确保配置正确)。
中间件优化:
建议替换自定义权限检查逻辑,使用ASP.NET Core标准的UseAuthorization()中间件,更贴合框架规范:app .UseAuthentication() .UseAuthorization() .UseFileServer() .UseGiraffe(webApp)之后在Giraffe路由上添加
[<Authorize>]特性保护接口即可。日志排查:
开启详细日志定位具体失败原因,在appsettings.json中添加:"Logging": { "LogLevel": { "Microsoft.Identity.Web": "Debug", "Microsoft.AspNetCore.Authentication": "Debug" } }日志会明确显示是密钥缺失、签名不匹配还是受众错误导致的验证失败。
内容的提问来源于stack exchange,提问作者Marko Grdinić

