多个 HTTP 授权标头?

Posted

技术标签:

【中文标题】多个 HTTP 授权标头?【英文标题】:Multiple HTTP Authorization headers? 【发布时间】:2015-05-30 17:05:56 【问题描述】:

是否可以在 HTTP 消息中包含多个授权标头?具体来说,我想包括 Bearer 令牌类型之一(传递 OAuth 访问令牌)和 Basic 类型之一(传递 base64 编码的用户名:密码)。

GET /presence/alice HTTP/1.1 
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM
Authorization: Basic YXNkZnNhZGZzYWRmOlZLdDVOMVhk

我认为这不应该是不可能的,只是想与社区一起审查以确定。

【问题讨论】:

c.f. ***.com/questions/3761845/… 【参考方案1】:

**** 2021 年 2 月更新 *** 请阅读本回复的 cmets。他们的一般结论似乎是一些 Web 服务器接受多个授权方案,但它违反了 RFC 7230/7235 ****

这应该是可能的,你只需要在字段值之间添加一个逗号,例如:

GET /presence/alice HTTP/1.1 
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM, Basic YXNkZnNhZGZzYWRmOlZLdDVOMVhk

这在RFC7230,第 3.2.2 节,字段顺序中定义:

发送者不得在消息中生成多个具有相同字段名称的头字段,除非该头字段的整个字段值定义为逗号分隔列表 [即,#(values)] 或头字段是一个众所周知的例外(如下所述)。

接收者可以将多个具有相同字段名称的标头字段组合成一个“字段名称:字段值”对,而不改变消息的语义,方法是将每个后续字段值按顺序附加到组合的字段值中,用逗号分隔。因此,接收具有相同字段名称的头字段的顺序对组合字段值的解释很重要;转发消息时,代理不得更改这些字段值的顺序。

我不知道是否所有网络服务器都接受这一点 - 在撰写本文时,我正在与一位同事就它是否应该工作进行辩论。

【讨论】:

答案似乎是否定的——至少在 Apache 2.4 中没有。 我认为这应该是公认的答案。用逗号对我来说很完美。基本身份验证和 JWT。 没有。该部分仅适用于 entire 字段值定义为逗号分隔列表的标头,例如 Accept-Encoding 标头。但是,Authorization 标头的字段值是 not defined like that。 @Sam Critchley 标头有一个凭据字段,凭据字段由两部分组成:身份验证方案和参数/参数列表。参数可以用逗号分隔,但是,不,整个凭据字段不是一个列表。 (凭证是复数在这里并不重要——它是一个标量值。) 这是一个错误的实现!请参阅 RFC,附录 C:tools.ietf.org/html/rfc7235#appendix-C 授权不是逗号分隔的列表。如果服务器接受它,它就没有按照 RFC 实现协议。【参考方案2】:

不,这是不可能的。语法定义见http://greenbytes.de/tech/webdav/rfc7235.html#header.authorization

【讨论】:

虽然我应该相信你,因为我知道你是谁,但你所说的与规范不一致:“在创建他们的值时,用户代理应该通过选择挑战来做到这一点它认为是它理解的最安全的身份验证方案,并酌情从用户那里获取凭据。” — 具体来说,1)“应该”,2)token68 不包括“,”,这意味着逗号不会被解释为令牌的一部分,以及 3)规范中没有说多重身份验证。无法提供标头,即 2 个标头 CRLF 分隔。另见github.com/nickstenning/nginx-multiauth 当使用列表语法定义时,您只能使用多个头字段;见greenbytes.de/tech/webdav/rfc7230.html#rfc.section.3.2.2.p.2 @JulianReschke 我们能否在同一个请求中设置包含基本身份验证的第一个授权标头,并设置包含承载身份验证的第二个授权标头? 不,那将是无效的语法。【参考方案3】:

我也有类似的问题。这似乎是一个很普遍的问题 (Link to question)。我最终将不记名令牌的授权标头更改为非标准标头,例如

X-Auth:Bearer mF_9.B5f-4.1JqM

这样,它只是另一个 HTTP 标头,基本的 http 授权将通过。如果您正在开发自己的 API,这应该没问题。

一些进一步的研究

基于RFC 2617,这里有一些有趣的细节。

用户代理必须 选择使用具有最强身份验证方案的挑战之一 基于此理解并请求用户提供凭据 挑战。

请注意,许多浏览器只能识别 Basic 并且需要 这是第一个提出的身份验证方案。服务器应该只 如果最低限度可以接受,则包括 Basic。

【讨论】:

RFC 2617 现在已经无关紧要了。您需要检查 RFC 7235。【参考方案4】:

标题fields are key/value pairs。所以只要它们是独一无二的并且你/程序员知道谁是谁,这很好

AuthorizationBearer: Bearer mF_9.B5f-4.1JqM
AuthorizationBasic: Basic YXNkZnNhZGZzYWRmOlZLdDVOMVhk

我的 Angular 拦截器将 Authorization111: Bearer xyz123 发送到 Node API,API 将令牌提取为

var token = header.headers["authorization111"].toString().split(' ')[1];

【讨论】:

我认为这是一个很好的答案,但是我有一个条件确保值中有一个空格,否则服务器会吐出一个逻辑错误。 @FiddleFreak 你能解释一下细节吗? 我会直接停在const arrAuthHeader = req.get('Authorization').split(" ");,然后使用两个 if 条件检查变量 > if (!arrAuthHeader)if(arrAuthHeader.length < 2)。所以你可以正确地抛出错误。然后你就做const bearer = arrAuthHeader[0];const token = arrAuthHeader[1];的作业【参考方案5】:

如果您在后端使用 python,那么您可以简单地将 dict 传递给 Bearer,然后在后端处理它之前执行 json.loads

这样您可以在一个授权标头中传递多个值

示例:通过"access_token" : access_token, "app_id" : 2

后台json.loads(""access_token" : access_token, "app_id" : 2")

【讨论】:

【参考方案6】:

可能有多个授权标头,我在集成接受多个授权的 API 时遇到了同样的问题。

这是调用接受多个身份验证令牌的 API 的 React js 示例。

axios.get(Constants.API+Constants.GET_USER,    headers: 
'Accept': 'application/json',
'Content-Type': 'application/json',
"Authorization": Constants.AUTH_Element + ',' + Constants.AUTH_ORG + ','+ 
Constants.AUTH_USER
)
.then(function (response) 
    // handle success
    console.log(response);
)
.catch(function (error) 
    // handle error
    console.log(error);
)
.finally(function () 
    // always executed
);

【讨论】:

问题是哪个API?

以上是关于多个 HTTP 授权标头?的主要内容,如果未能解决你的问题,请参考以下文章

HttpRequestMessage 多个自定义标头相互覆盖

添加多个自定义 http 请求标头之谜

是否可以在 HTTP 标头字段中包含多个 CRLF?

Angular 2/4 如何将多个标题添加到 http post

Yandex-tank - 具有不同 http 标头的多个请求

将单个 HTTP 标头的多个值添加到请求或响应的标准