You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue.js SPA调用带Azure AD授权的ASP.Net Core API返回401错误

编辑1:我最初以为应用部署到服务器后调用正常,但实际并非如此。

背景信息

  • 基于Vue.js(vue3组合式API)开发的单页应用(SPA)
  • 使用MSAL库(@azure/msal-browser@^2.32.2)实现Azure AD认证
  • ASP.Net Core Web API(.Net 7)
  • 通过Axios(axios@1.2.4)从SPA调用API
    • 请求拦截器通过MSAL获取访问令牌(JWT Bearer),并在请求中作为Authorization头发送。

问题现象

从SPA调用API时返回401未授权错误。

以下调用场景可正常工作:

  • 本地通过Swagger UI调用
  • 本地使用带--insecure参数的curl命令调用
  • 本地通过禁用证书验证的Insomnia工具调用
  • 服务器上部署的SPA调用同服务器上的API(原以为正常)
    编辑1:实际此场景也无法正常工作。
  • 本地SPA调用API中无需授权的接口

环境信息

  • Windows 10开发电脑
  • SPA通过Vite在本地运行
    • 使用vite preview运行构建版本时存在相同问题。
  • 测试使用Edge(Chromium内核),Firefox或其他Chromium内核浏览器也存在相同问题。
  • API通过IIS Express在本地运行(使用IIS Express生成的证书启用HTTPS)

由于服务器上的解决方案原以为正常,我曾认为Azure AD配置无误。
编辑1:Azure AD配置可能存在错误。

且由于可通过其他方式本地调用API,我认为API配置无误。

我猜测问题可能出在Axios调用上,但仅在本地且涉及授权时出现。

Azure AD配置情况

我按照官方教程配置Azure AD:

单页应用配置

遵循Azure AD JavaScript单页应用教程,使用MSAL与Azure AD交互。我还添加了Axios请求拦截器,为每个请求自动获取访问令牌。

Web API配置

遵循Azure AD ASP.NET API教程,授权配置中设置了带范围要求的策略,策略名为AuthZPolicy,我的范围名为access_as_user。

控制器使用特性[Authorize(Policy = "AuthZPolicy")]修饰。

我理解的认证/授权流程如下:

  1. 用户使用公司凭据完成认证
  2. MSAL获取IdToken并存储到本地存储中
  3. 当页面发起请求时,拦截器通过MSAL获取访问令牌,该令牌包含声明"scp": "access_as_user"。
  4. 访问令牌在请求的Authorization头发送给API。
  5. 此时我预期API会验证令牌并返回响应,但实际返回401错误。
已尝试的排查手段

禁用授权

我尝试通过移除控制器上的Authorize特性来禁用API的授权。

也可通过在授权配置中不指定任何范围来禁用授权:

builder.Services.AddAuthorization(config =>
{
    config.AddPolicy("AuthZPolicy", policyBuilder =>
        policyBuilder.Requirements.Add(new ScopeAuthorizationRequirement(/* no scopes required */)));
}

两种方式下调用均可返回预期数据,但这不符合我们的授权需求。

为SPA启用HTTPS

我原本通过HTTP启动SPA,改为通过HTTPS启动(使用@vitejs/plugin-basic-ssl)后问题仍存在。

在Axios中禁用rejectUnauthorized

我希望将rejectUnauthorized设为false,以达到curl的--insecure参数或Insomnia禁用证书验证的效果。

但无法实现,因为浏览器环境中无法使用"https"模块,报错如下:

Module "https" has been externalized for browser compatibility. Cannot access "https.Agent" in client code. See vite官方故障排除文档了解更多详情。

我未尝试设置自定义证书,因为不清楚具体操作步骤。我推测需要为IIS Express配置证书,然后获取证书链来配置Axios。

调用详情

SPA发起的调用(失败)

在开发者工具中可看到以下信息:

通用请求头

Request URL: https://localhost:44342/api/Reason/GetAll
Request Method: GET
Status Code: 401 
Remote Address: [::1]:44342
Referrer Policy: strict-origin-when-cross-origin

响应头

access-control-allow-credentials: true
access-control-allow-origin: https://localhost:44340
access-control-expose-headers: Content-Disposition
date: Fri, 02 Jun 2023 14:07:59 GMT
server: Microsoft-IIS/10.0
vary: Origin
www-authenticate: Bearer
x-powered-by: ASP.NET

请求头

:authority: localhost:44342
:method: GET
:path: /api/Reason/GetAll
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: fr,fr-FR;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
authorisation: Bearer t0K3n
origin: https://localhost:44340
referer: https://localhost:44340/
sec-ch-ua: "Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.57

API日志

在API控制台中可看到以下日志:

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 OPTIONS https://localhost:44342/api/Reason/GetAll - -
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
      CORS policy execution successful.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/2 OPTIONS https://localhost:44342/api/Reason/GetAll - - - 204 - - 0.4755ms
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/2 GET https://localhost:44342/api/Reason/GetAll - -
info: Microsoft.AspNetCore.Cors.Infrastructure.CorsService[4]
      CORS policy execution successful.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed. These requirements were not met:
      ScopeAuthorizationRequirement:Scope=
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
      AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/2 GET https://localhost:44342/api/Reason/GetAll - - - 401 - - 0.5798ms

尽管访问令牌中包含该范围,但仍出现以下日志:

Authorization failed. These requirements were not met:
ScopeAuthorizationRequirement:Scope=

Swagger UI发起的调用(成功)

启动API时会打开Swagger UI。
如果使用从开发者工具请求头中复制的令牌在Swagger UI中认证,可返回200状态码及预期结果。

curl发起的调用(带--insecure参数时成功)

Swagger UI生成的curl命令如下:

curl -X 'GET' \
  'https://localhost:44342/api/Reason/GetAll' \
  -H 'accept: text/plain' \
  -H 'Authorization: Bearer t0K3n'

在Git Bash终端中执行时,会出现以下错误:

curl: (60) SSL certificate problem: self signed certificate
More details here: curl官方sslcerts文档

curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.

我理解这是因为API运行在使用自签名证书的IIS Express上。

使用--insecure参数时可返回预期结果。

Insomnia发起的调用(禁用证书验证时成功)

Insomnia是一款REST API测试工具。
与curl类似,当Insomnia验证服务器证书时会报错,但禁用证书验证后可返回预期响应。

内容的提问来源于stack exchange,提问作者Xavier Stévenne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 16:22:05