自定义授权头

31

我知道在 Stack Overflow 上已经有足够的关于这个问题的内容了,但我的主题与其他人不同(有点相似但不完全相同)。

我想听听社区对我所做的事情的想法,看看是否可以在某些地方进行改进。

目前我正在使用基本授权(BASIC Authorization)作为我的登录 EndPoint,因为它不需要复杂性,并且它是通过 https 进行的,所以它现在的状态很好。

示例:

GET - /api/login

Authorization : Basic BASE64String(username:password)

我的一些 EndPoints 需要 Token 才能获得资源访问权限。这些 Token 我通过 Headers 和 Https-Secured 发送。

问题在于我没有使用传统的授权方法。以下是一些示例:

示例1:

GET - /api/hardware/{PUBLIC_TOKEN}/getMe

Authorization-Hardware : PRIVATE_TOKEN

这个 EndPoint 不需要 Authorization-Hardware Header,但如果包含,API 将执行更多操作。(这里不相关)

示例2:

GET - /api/login/{id}

Authorization-Person : USER_TOKEN

否则需要包含 Authorization-Person Header 和 User Token 才能访问该资源。(注意 Token 的生成方式在这里不重要)

必须使用 HTTPS 请求才能访问 API EndPoints。

我给上面的自定义 Headers 和 EndPoints 随意取了一些名称,只是为了让大家看到我的授权架构,并不代表实际名称。所以请不要关注名称,只需关注架构即可。

我的问题是:不遵循传统方式是否很糟糕?创建自定义授权 Headers 是否有什么问题(如果有,原因是什么)。

我认为这种方式更简单地提供授权和安全地传递 Tokens,所有这些 Tokens 可以在平台上重新生成。

许多设备和移动应用程序已经使用此架构,但都处于开发环境中,还没有进入生产环境。我的担忧是,这种非传统方式可能会影响 API 的用户。希望社区的想法可以帮助我改进。

编辑:2017年3月26日

我想知道,是否最好按照协议中描述的方式来实现,并且为什么。因为当需要多个授权时,按照协议来处理 Authorization Header 比具有自定义 Header 并想要检索其值更困难。

遵循协议,您应该像这样使用 Authorization Header:

Authorization: <type> <value>

示例:

GET - /api/login/{id}

Authorization : User USER_TOKEN

但我无法看到遵循这种方法的好处,因为当获取它的值时,会返回一个字符串,或者在示例中返回用户令牌。

使用自定义标头更容易验证令牌,多个授权可能也会按照协议方式导致麻烦。


我真的需要一些帮助,我越来越接近完成这个产品了! - Igor Morse
1个回答

48
TL;DR 一些头部名称(如Authorization)有特殊的缓存规则和代理客户端处理规则;除非您修改每个代理和客户端,否则您的自定义头部名称将不会获得特殊行为。
使用在RFC7234中定义的通用Authorization: <type> <value>标题的主要目的是确保本地实现这些标题处理的客户端和HTTP代理正确地行为。
RFC7234的第4.2节说:
“转发请求的代理服务器不得修改该请求中的任何授权字段。有关HTTP缓存处理授权字段的详细信息和要求,请参见[RFC7234]的第3.2节。”
代理可以修改、省略、记录或缓存其他Authorization-*头部。

RFC7234, section 3.2指出请求/响应中的Authorization头部不得被缓存(除了特定情况)。

RFC7235, section 5.1.2, point 7进一步说明了使用除Authorization之外的头部的新身份验证方案:

因此,选择不在Authorization头字段中携带凭据的新身份验证方案(例如,使用新定义的头字段)将需要明确禁止缓存,通过强制使用Cache-Control请求指令(例如,“no-store”,[RFC7234]的第5.2.1.5节)或响应指令(例如,“private”)。

那么你应该怎么做呢?如果你完全控制系统的两端,定义一个新的类型值来覆盖一个或多个令牌类型的任何组合,避免使用,字符是可以接受的。

Authorization: MyAuth User=USER_TOKEN/Hardware=HWTOKEN/Person=PERSONTOKEN/Basic=...

另一种方式取决于服务器和客户端的实现,可以使用,作为多个标头的备用版本列表形式:

Authorization: User USER_TOKEN, Hardware=HWTOKEN, Person=PERSONTOKEN, Basic=...

这取决于服务器和客户端,可能被视为与以下内容相同:

Authorization: User USER_TOKEN
Authorization: Hardware HWTOKEN
Authorization: Person PERSONTOKEN
Authorization: Basic ...

这里的问题是“MAY”(大量强调)可能被视为相同。有讨论建议,不同版本的Apache和NGINX并不一致地处理它,并且旧的HTTP RFC对预期行为非常不清楚。

这是关于这个主题的很好的启发!谢谢!我仍在考虑我应该使用什么,但我会尽量避免自定义名称头。 - Igor Morse
1
请查看https://tools.ietf.org/html/rfc7230#section-3.2.2,其中提到:“发送方不得在消息中生成具有相同字段名称的多个标头字段,除非该标头字段的整个字段值被定义为逗号分隔列表[即,#(values)]或标头字段是众所周知的例外情况(如下所述)。 - wonhee
1
此外,“接收者可以将具有相同字段名称的多个头字段组合成一个“字段名称:字段值”对,通过按顺序将每个后续字段值附加到组合字段值中,用逗号分隔,而不改变消息的语义。因此,具有相同字段名称的标头字段接收顺序对于解释组合字段值至关重要;代理在转发消息时不得更改这些字段值的顺序。”说到这里,使用多个授权模式似乎是有效的,但对于后面的那个则不行。 - wonhee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接