我想在客户端脚本中检测到在使用错误的 PAT 获取数据时出现 401 错误(使用 Azure DevOps REST API)

问题描述 投票:0回答:1

当我使用过期的 PAT 尝试访问 REST 端点时,在浏览器的开发工具控制台窗口中我将得到:

GET https://dev.azure.com/contoso/_apis/connectionData net::ERR_FAILED 401 (Unauthorized)

但是从 JavaScript 内部不可能得到 401 状态码这一事实。 我尝试过使用“then”/“catch”/获取并使用try/catch等待。 我也尝试过 XMLHttpRequest。 我得到的唯一错误是:

TypeError: Failed to fetch

由于浏览器清楚地看到

401 (Unauthorized)
,我想检测到该状态代码。

浏览器开发工具控制台还具有以下功能:

Access to fetch at 'https://dev.azure.com/contoso/_apis/connectionData' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

enter image description here

“网络”选项卡还显示 401 状态:

enter image description here

使用

no-cors
隐藏会使所有内容变得不透明,并且您不会获得 401 状态。

这是一个可运行的示例:

<!DOCTYPE html>
<html>
  <body>
    <script>
(async function () {
  "use strict";

  const API_ORGANIZATION="contoso"

  const expiredPat = 'ts44tplifj4hbbzeitcz5dg5az4q3mpqcxqmrxo4zwlgy3scobzq'
  const pat = expiredPat

  // Fetch data from Azure DevOps
  async function ado(api) {
    const url = `https://dev.azure.com/${API_ORGANIZATION}/_apis/${api}`
    console.log(`url: ${url}`)
    const response = await fetch(url, {
      method: 'GET',
      cache: 'no-cache',
      mode: 'cors',
      headers: {
        Authorization: 'Basic ' + btoa(':' + pat),
        Accept: 'application/json',
      }
    })
    return await response.json()
  }

  // get the connectionData from Azure DevOps
  async function getConnectionData() {
    return await ado('connectionData')
  }

  function topText(text) {
    var p = document.createElement('p');
    p.innerHTML = text
    document.body.prepend(p)
    return p
  }

  // show the connection Data at the top of the window
  async function showConnectionData() {
    try {
      const result = await getConnectionData();
      topText(`Azure DevOps access authenticated as: ${result.authenticatedUser.providerDisplayName}`)
    } catch(err) {
      const p = topText(`${err} - See console`)
      p.style.color = "red";
      p.style.fontWeight = "999"
    }
  }

  async function tryFetch() {
    try {
      await showConnectionData()
    } catch(err) {
      console.log(err);
    }
  }

  document.addEventListener("DOMContentLoaded", function(event) {
    tryFetch()
  });

})();


    </script>
  </body>
</html>

javascript azure-devops browser cors fetch-api
1个回答
0
投票

该问题是由 CORS(跨源资源共享)引起的。

根据这个官方文档关于Azure DevOps REST API:

Azure DevOps Services 支持 CORS,这使得从 dev.azure.com/* 以外的域提供的 JavaScript 代码能够向 Azure DevOps Services REST API 发出 Ajax 请求。每个请求都必须提供凭据(PAT 和 OAuth 访问令牌都是受支持的选项)。

这意味着当您提供正确的凭据时,Azure DevOps Services 支持 CORS。当 PAT 不正确时,服务器会响应 401 未经授权状态,并且由于凭据无效,服务器不会继续处理请求,也不包含 CORS 标头。

例如,我使用以下脚本测试了该问题(将 orgname 和 pat 替换为实际值):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Azure DevOps CORS Example</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
    <h1>Azure DevOps API Response</h1>
    <div id="status"></div>
    <div id="response"></div>
    <script>
        $(document).ready(function() {
            $.ajax({
                url: 'https://dev.azure.com/{orgname}/_apis/connectionData',
                dataType: 'json',
                headers: {
                    'Authorization': 'Basic ' + btoa("" + ":" + "pat")
                }
            }).done(function(results) {
                $('#status').text('Status: 200 OK');
                $('#response').text(JSON.stringify(results, null, 2));
            }).fail(function(jqXHR, textStatus, errorThrown) {
                $('#status').text('Status: ' + jqXHR.status + ' ' + textStatus);
                $('#response').text('Response: ' + errorThrown);
            });
        });
    </script>
</body>
</html>

使用正确的 PAT 运行脚本时,您可以在响应标头中看到

Access-Control-Allow-Origin:*

correct PAT

使用过期的 PAT 运行脚本时,响应标头中没有

Access-Control-Allow-Origin:*

expired PAT

要解决 CORS 问题,您可以参考此问题了解更多详细信息。

在我的测试中,我尝试使用 CORS Anywhere,这是 CORS Anywhere 服务的公开演示。它允许您在向不同域发出请求时绕过 CORS 限制。这只能用于开发目的。

步骤:

  1. 访问 https://cors-anywhere.herokuapp.com/corsdemo 并单击“请求临时访问演示服务器”按钮。您将可以临时访问演示服务器。
  2. https://cors-anywhere.herokuapp.com
    添加到脚本中的 URL,即变为
    https://cors-anywhere.herokuapp.com/https://dev.azure.com/orgname/_apis/connectionData
  3. 现在我们可以在响应头中找到
    Access-Control-Allow-Origin:*
    并获取401状态码。

测试结果: result

© www.soinside.com 2019 - 2024. All rights reserved.