访问令牌错误时返回 401 状态

401 Status Returned on Access Token Errors

虽然 401 Unauthorized 对于这些(“访问令牌丢失或无效”)可能看起来很漂亮,但它可以抛出许多客户端 HTTP 堆栈来提示用户输入凭据,这无论如何都不会成功,因为正常的 HTTP 身份验证机制不起作用。

虽然我可以使用另一个客户端库来绕过它,但我可以指示它不要尝试自动身份验证或用户提示(并且已经这样做了),据我所知,这似乎违反了 RFC 7235

我怀疑 403 Forbidden 在这里会更合规,并且对 API 用户来说会更少悲伤。他们中的大多数人可能只是看到任何非 2XX 状态并立即 运行 寻找 JSON“错误”响应正文。

我走了弯路所以我没有抱怨,但这里似乎有些可疑。当然我错过了什么?现在以这种方式将 401 用于类似 REST 的 HTTP APIs 是常见的做法吗?

更多详情

只要使用正确的身份验证令牌,它就可以工作,但如果使用了错误的令牌,则会导致 GUI 提示 user/pw:

Set JsonBag = PBConfig.CloneItem("CreatePushJson") 'Make a deep copy of template JSON.
With JsonBag
    .Item("title") = txtTitle.Text
    .Item("body") = txtBody.Text
End With

With XMLHTTP
    .abort 'Clean up previously failed request if any.
    .open "POST", PBConfig.Item("CreatePushUrl"), True
    .setRequestHeader "Access-Token", PBConfig.Item("AccessToken")
    .setRequestHeader "Content-Type", "application/json"
    .onreadystatechange = SinkRSChange
    .send JsonBag.JSON
End With

如果提示被用户取消,则 401 会报告给代码。

根据以下信息,我尝试将身份验证令牌作为用户 ID 值发送。然而,即使身份验证令牌正确,这也会引发提示:

Set JsonBag = PBConfig.CloneItem("CreatePushJson") 'Make a deep copy of template JSON.
With JsonBag
    .Item("title") = txtTitle.Text
    .Item("body") = txtBody.Text
End With

With XMLHTTP
    .abort 'Clean up previously failed request if any.
    .open "POST", PBConfig.Item("CreatePushUrl"), True, PBConfig.Item("AccessToken")
    .setRequestHeader "Content-Type", "application/json"
    .onreadystatechange = SinkRSChange
    .send JsonBag.JSON
End With

如果用户在提示中手动输入有效的身份验证令牌作为用户 ID,则请求成功。

根据以下新信息

这可以通过明确发送 "." 作为密码来实现:

Set JsonBag = PBConfig.CloneItem("CreatePushJson") 'Make a deep copy of template JSON.
With JsonBag
    .Item("title") = txtTitle.Text
    .Item("body") = txtBody.Text
End With

With XMLHTTP
    .abort 'Clean up previously failed request if any.
    .open "POST", PBConfig.Item("CreatePushUrl"), True, PBConfig.Item("AccessToken"), "."
    .setRequestHeader "Content-Type", "application/json"
    .onreadystatechange = SinkRSChange
    .send JsonBag.JSON
End With

正确的令牌值有效,错误的令牌值 returns 401 可以处理。现在没有凭据提示对话框。

从技术上讲,正常的 HTTP 身份验证机制正在发挥作用。 api 甚至要求您的浏览器提供凭据,以便您可以在浏览器中执行请求(实际上有人请求了)。

对 401 具有特殊行为的 HTTP 库似乎确实是个问题,但有一次它发生了,我能够禁用神奇的 401 处理。我不知道谁在这里违反了 RFC 7235。 RFC 2616 10.4.2 似乎表明当前行为是 "correct"。您是否有提示用户输入凭据的 HTTP 客户端列表?

也许 403 在这里更有意义,但 Stripe 至少似乎使用了 401:https://stripe.com/docs/api#errors 而且它们都是关于 REST 的。切换到 403 也会破坏所有现有客户端。大多数客户端实际上并没有足够奇怪地查看 JSON 主体,他们只是查看状态代码。

我认为如果我创建另一个 HTTP API,它将只有 200/400/500 个状态代码,其中 POST 个 JSON 编码主体和 JSON 响应。

选择:

如果不需要支持 Windows 的下级版本,您可以使用 WinHttp.WinHttpRequest 对象替代上述问题示例中使用的 MSXML2.XMLHTTP 对象。

Set JsonBag = PBConfig.CloneItem("CreatePushJson") 'Make a copy.
JsonBag("title") = txtTitle.Text
JsonBag("body") = txtBody.Text

With WinHttp
    .Abort 'Clean up previously failed request if any.
    .Open "POST", PBConfig("CreatePushUrl"), True
    .SetAutoLogonPolicy AutoLogonPolicy_Never
    .SetRequestHeader "Access-Token", PBConfig("AccessToken")
    .SetRequestHeader "Content-Type", "application/json"
    .Send JsonBag.JSON
End With

关键是 .SetAutoLogonPolicy AutoLogonPolicy_Never 我们没有旧版 class。

请注意,此示例利用了一个事实,即 JsonBag 将 .Item() 作为其默认值 属性...那些。它与 WinHttp 的使用无关,也可以在早期的代码片段中以这种方式编写。