ASP.NET Core 2.0 Web API Azure AD JWT签名无效及令牌适配问题
看起来你在Azure AD令牌版本混用和On-Behalf-Of(OBO)流程上踩了好几个典型的坑,我来帮你逐一理清问题根源:
1. 为什么ADAL的V1令牌能过Graph,但Web API返回"Invalid Signature"?
这个问题的核心是V1令牌的发行者格式和你Web API配置的Authority不匹配。ASP.NET Core 2.0的JWT中间件默认会严格验证Issuer,而Azure AD V1令牌的Issuer是https://sts.windows.net/TENANT_ID/(注意末尾的斜杠),但你配置的Authority是https://login.microsoftonline.com/TENANT_ID,两者格式不一致,导致签名验证失败。
解决办法是调整Web API的JWT验证参数,明确指定V1令牌的ValidIssuer:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Authority = "https://login.microsoftonline.com/TENANT_ID"; options.Audience = "CLIENT_ID"; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "https://sts.windows.net/TENANT_ID/", // 匹配V1令牌的发行者格式 ValidateAudience = true, ValidAudience = "CLIENT_ID", ValidateIssuerSigningKey = true }; });
2. 为什么MSAL的V2令牌能过Web API,但调用Graph失败?
这是因为令牌的受众(Audience)不对。你用MSAL获取的V2令牌,受众是Web API的CLIENT_ID,而不是Microsoft Graph的资源ID。Graph不会接受受众不是自己的令牌,自然会返回失败。
正确的做法是:不要让SPA直接拿Graph令牌给Web API,而是让Web API通过OBO流程,用SPA传来的用户令牌去申请Graph的访问令牌——这才是后端API调用Graph的标准方式。
3. 为什么用V2令牌做用户断言时,AcquireTokenAsync抛出版本不匹配错误?
这个问题通常有两个原因:
- 你用了V1的OBO端点来处理V2令牌:V2令牌必须对应V2的令牌端点
https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token,如果你的MSAL配置还是指向V1的Authority,就会触发这个错误。 - Scope格式不正确:V2流程中请求Graph权限时,必须用完整的Scope格式(比如
https://graph.microsoft.com/User.Read),而不是V1的短格式。
解决办法是确保你的MSAL客户端配置用V2的Authority,并且请求正确的Graph Scope:
// 初始化MSAL机密客户端,指定V2端点 var confidentialClient = ConfidentialClientApplicationBuilder .Create("WEB_API_CLIENT_ID") .WithClientSecret("WEB_API_CLIENT_SECRET") .WithAuthority(new Uri("https://login.microsoftonline.com/TENANT_ID/v2.0")) .Build(); // 用用户的V2令牌做断言,申请Graph令牌 var result = await confidentialClient.AcquireTokenOnBehalfOf( new[] { "https://graph.microsoft.com/User.Read" }, // 完整的Graph Scope new UserAssertion(userJwtTokenFromSPA)) .ExecuteAsync();
总结建议:统一用V2流程
为了避免版本混用的麻烦,建议你全链路切换到V2:
- 确保SPA和Web API都在Azure AD的V2端点注册(或开启V2令牌支持);
- SPA用MSAL获取Web API的令牌,请求的Scope是你为Web API定义的自定义Scope(比如
api://WEB_API_CLIENT_ID/access_as_user); - Web API的JWT验证配置用V2的Authority和Issuer;
- Web API通过MSAL的OBO流程,用用户令牌申请Graph的V2令牌。
另外,你可以用jwt.ms解码令牌,检查Issuer、Audience、Scopes等字段是否符合预期,这是快速排查令牌问题的好工具。
内容的提问来源于stack exchange,提问作者Abraxas

