提问人:deceze 提问时间:5/20/2011 更新时间:12/12/2021 访问量:166194
会话真的违反了 RESTfulness 吗?
Do sessions really violate RESTfulness?
问:
在 RESTful API 中使用会话真的违反了 RESTfulness 吗?我看到很多意见都朝着这两个方向发展,但我不相信会议是无休止的。从我的角度来看:
- RESTfulness 不禁止身份验证(否则在 RESTful 服务中几乎没有用处)
- 身份验证是通过在请求中发送身份验证令牌(通常是标头)来完成的
- 此身份验证令牌需要以某种方式获取,并且可能会被吊销,在这种情况下,需要续订
- 身份验证令牌需要由服务器验证(否则不会是身份验证)
那么会话是如何违反这一点的呢?
- 客户端,会话是使用 cookie 实现的
- Cookie 只是一个额外的 HTTP 标头
- 可以随时获取和撤销会话 cookie
- 如果需要,会话 cookie 可以具有无限的生命周期
- 会话 ID(身份验证令牌)在服务器端进行验证
因此,对于客户端来说,会话cookie与任何其他基于HTTP标头的身份验证机制完全相同,只是它使用标头而不是其他专有标头。如果没有会话附加到服务器端的 cookie 值,为什么会有所不同?只要服务器的行为是 RESTful 的,服务器端实现就不需要关注客户端。因此,Cookie 本身不应使 API 成为 RESTless,会话只是客户端的 Cookie。Cookie
Authorization
我的假设错了吗?是什么让会话 Cookie 变得无 RESTless?
答:
首先,REST不是一种宗教,不应该这样对待。虽然 RESTful 服务有一些优点,但您应该只遵循 REST 的原则,只要它们对你的应用程序有意义。
也就是说,身份验证和客户端状态并不违反 REST 原则。虽然REST要求状态转换是无状态的,但这指的是服务器本身。从本质上讲,所有REST都是关于文档的。无状态背后的思想是服务器是无状态的,而不是客户端。任何发出相同请求(相同标头、cookie、URI 等)的客户端都应被带到应用程序中的同一位置。如果网站通过更新此服务器端导航变量来存储用户的当前位置和托管导航,则将违反 REST。另一个具有相同请求信息的客户端将被带到不同的位置,具体取决于服务器端状态。
Google 的 Web 服务是 RESTful 系统的一个很好的例子。它们要求在每个请求时传递带有用户身份验证密钥的身份验证标头。这确实略微违反了 REST 原则,因为服务器正在跟踪身份验证密钥的状态。必须保持此密钥的状态,并且它具有某种到期日期/时间,在此日期/时间之后,它将不再授予访问权限。但是,正如我在帖子顶部提到的,必须做出牺牲才能让应用程序真正工作。也就是说,身份验证令牌的存储方式必须允许所有可能的客户端在其有效时间内继续授予访问权限。如果一台服务器正在管理身份验证密钥的状态,以至于另一台负载平衡服务器无法接管基于该密钥的请求,那么您就开始真正违反 REST 的原则了。 Google 的服务确保您可以随时将手机上使用的身份验证令牌用于负载平衡服务器 A,然后从桌面访问负载平衡服务器 B 并且仍然可以访问发送到系统,如果请求相同,则定向到相同的资源。
归根结底,您需要确保根据某种后备存储(数据库、缓存等)验证身份验证令牌,以确保保留尽可能多的 REST 属性。
我希望所有这些都是有道理的。如果您还没有的话,您还应该查看维基百科文章中关于具象状态转移的约束部分。关于REST的原则实际上在争论什么以及为什么,它特别有启发性。
评论
- 会话不是无 RESTless 的
- 你的意思是REST服务仅供http使用还是我弄错了?基于 Cookie 的会话只能用于 own(!) http-based services!(使用cookie可能是一个问题,例如来自移动/控制台/桌面/等)
- 如果您为 3D 方开发人员提供 RESTful 服务,请不要使用基于 cookie 的会话,而是使用令牌以避免安全问题。
评论
Cookie 不用于身份验证。为什么要重新发明轮子?HTTP 具有精心设计的身份验证机制。如果我们使用 cookie,我们就会陷入仅使用 HTTP 作为传输协议,因此我们需要创建自己的信令系统,例如,告诉用户他们提供了错误的身份验证(使用 HTTP 401 是不正确的,因为我们可能不会向客户端提供,因为 HTTP 规范要求:) )。还应该注意的是,这只是对客户的建议。其内容可能会被保存,也可能不会被保存(例如,如果 cookie 被禁用),而标头会在每次请求时自动发送。Www-Authenticate
Set-Cookie
Authorization
另一点是,要获取授权 cookie,您可能希望先在某个地方提供您的凭据?如果是这样,那岂不是RESTless吗?简单示例:
- 您尝试不使用 cookie
GET /a
- 您以某种方式收到授权请求
- 你去以某种方式授权,就像
POST /auth
- 你得到
Set-Cookie
- 您尝试使用cookie。但是在这种情况下,行为是否具有幂等性?
GET /a
GET /a
总而言之,我认为,如果我们访问某些资源并且需要进行身份验证,那么我们必须在同一资源上进行身份验证,而不是在其他任何地方进行身份验证。
评论
Authorization: Basic
Digest
Authorization
GET /a
没有 cookie 和有 cookie 显然是两个不同的请求,它们的行为不同是可以接受的。
GET /a
GET /a
首先,让我们定义一些术语:
宁静:
可以描述符合REST约束的应用程序 在本节中描述为“RESTful”。[15] 如果某项服务违反了任何 在所需的约束中,它不能被视为 RESTful。
根据维基百科。
无状态约束:
接下来,我们向客户端-服务器交互添加一个约束: 通信本质上必须是无状态的,如 第 3.4.3 节的 client-stateless-server (CSS) 样式(图 5-3), 这样,从客户端到服务器的每个请求都必须包含所有 理解请求所需的信息,并且不能采取 服务器上任何存储上下文的优势。会话状态为 因此完全保留在客户端上。
根据菲尔丁的论文。
因此,服务器端会话违反了 REST 的无状态约束,因此也违反了 RESTfulness。
因此,对于客户端来说,会话 cookie 与任何会话 cookie 完全相同 其他基于 HTTP 标头的身份验证机制,但其使用 Cookie 标头而不是 Authorization 或其他一些 专有标头。
通过会话 cookie,您可以将客户端状态存储在服务器上,因此您的请求具有上下文。让我们尝试将负载均衡器和另一个服务实例添加到您的系统中。在这种情况下,您必须在服务实例之间共享会话。很难维护和扩展这样的系统,所以它的扩展性很差......
在我看来,饼干没有错。Cookie 技术是一种客户端存储机制,其中存储的数据会通过每个请求自动附加到 Cookie 标头。我不知道REST约束在这种技术上有问题。所以技术本身没有问题,问题在于它的使用。菲尔丁写了一个小节,说明为什么他认为HTTP cookie是坏的。
从我的角度来看:
- RESTfulness 不禁止身份验证(否则在 RESTful 服务中几乎没有用处)
- 身份验证是通过在请求中发送身份验证令牌(通常是标头)来完成的
- 此身份验证令牌需要以某种方式获取,并且可能会被吊销,在这种情况下,需要续订
- 身份验证令牌需要由服务器验证(否则不会是身份验证)
你的观点非常坚定。唯一的问题是在服务器上创建身份验证令牌的概念。你不需要那部分。您需要的是将用户名和密码存储在客户端上,并在每次请求时发送。除了 HTTP 基本身份验证和加密连接之外,您不需要更多功能来执行此操作:
- 图 1.- 受信任客户端的无状态身份验证
您可能需要在服务器端使用内存中身份验证缓存来加快速度,因为您必须对每个请求进行身份验证。
现在,由您编写的受信任的客户端可以很好地工作,但是第三方客户端呢?他们不能拥有用户名和密码以及用户的所有权限。因此,您必须单独存储第三方客户端可以由特定用户拥有的权限。因此,客户端开发人员可以注册他们的第三方客户端,并获得唯一的 API 密钥,用户可以允许第三方客户端访问他们的部分权限。比如阅读姓名和电子邮件地址,或列出他们的朋友等......允许第三方客户端后,服务器将生成访问令牌。第三方客户端可以使用这些访问令牌来访问用户授予的权限,如下所示:
- 图2.- 第三方客户端的无状态身份验证
因此,第三方客户端可以从受信任的客户端(或直接从用户)获取访问令牌。之后,它可以使用 API 密钥和访问令牌发送有效请求。这是最基本的第三方身份验证机制。您可以在每个第三方身份验证系统(例如 OAuth)的文档中阅读有关实现细节的更多信息。当然,这可能更复杂、更安全,例如,您可以在服务器端签署每个请求的详细信息,并将签名与请求一起发送,等等......实际解决方案取决于您的应用程序的需求。
评论
实际上,RESTfulness 仅适用于 RESOURCES,如通用资源标识符所示。因此,甚至谈论诸如标头,cookie等与REST有关的东西都不太合适。REST可以在任何协议上工作,即使它恰好是通过HTTP完成的。
主要的决定因素是:如果您发送一个 REST 调用,这是一个 URI,那么一旦调用成功发送到服务器,该 URI 是否返回相同的内容,假设没有执行任何转换(PUT、POST、DELETE)?此测试将排除返回的错误或身份验证请求,因为在这种情况下,请求尚未到达服务器,这意味着将返回与给定 URI 对应的文档的 servlet 或应用程序。
同样,在 POST 或 PUT 的情况下,您能否发送给定的 URI/有效负载,并且无论您发送多少次消息,它都将始终更新相同的数据,以便后续 GET 将返回一致的结果?
REST是关于应用程序数据的,而不是关于传输该数据所需的低级信息。
在下面的博客文章中,Roy Fielding 对整个 REST 理念做了一个很好的总结:
http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841
“RESTful 系统从一个稳态发展到 接下来,每个这样的稳态都是一个潜在的起始状态 以及潜在的最终状态。也就是说,RESTful 系统是一个未知数 遵循一组简单规则的组件数量,使它们 始终处于 REST 状态或从一个 RESTful 过渡 状态设置为另一个 RESTful 状态。每个状态都可以完全 由它所包含的表示形式和 它提供的转换,转换限制为 统一的一组动作是可以理解的。系统可能是 一个复杂的状态图,但每个用户代理只能看到 一次一个状态(当前稳态),因此每个 状态很简单,可以独立分析。用户 OTOH、 能够随时创建自己的过渡(例如,输入 URL、选择书签、打开编辑器等)。
至于身份验证问题,无论是通过cookie还是header完成,只要信息不是URI和POST有效负载的一部分,它实际上与REST完全无关。因此,关于无状态,我们只谈论应用程序数据。
例如,当用户在 GUI 屏幕中输入数据时,客户端会跟踪哪些字段已输入、哪些字段未输入、缺少任何必填字段等。这都是 CLIENT CONTEXT,不应由服务器发送或跟踪。发送到服务器的是需要在 IDENTIFIED 资源中(通过 URI)修改的完整字段集,以便该资源从一个 RESTful 状态转换到另一个 RESTful 状态。
因此,客户端会跟踪用户正在执行的操作,并且只向服务器发送逻辑上完成的状态转换。
评论
HTTP 事务(基本访问身份验证)不适用于 RBAC,因为基本访问身份验证每次都使用加密的用户名:密码进行标识,而 RBAC 中需要的是用户希望用于特定调用的角色。 RBAC 不验证用户名的权限,而是验证角色的权限。
您可以像这样进行连接:usernameRole:password,但这是不好的做法,而且效率也很低,因为当用户有更多角色时,身份验证引擎需要测试串联中的所有角色,并且每次调用都会再次测试。这将破坏RBAC最大的技术优势之一,即非常快速的授权测试。
因此,使用基本访问身份验证无法解决该问题。
为了解决这个问题,会话维护是必要的,根据一些答案,这似乎与REST相矛盾。
这就是我喜欢REST不应该被视为一种宗教的答案的原因。例如,在复杂的商业案例中,在医疗保健领域,RBAC 是绝对常见和必要的。如果他们不被允许使用REST,那将是一个遗憾,因为所有的REST工具设计者都会将REST视为一种宗教。
对我来说,通过HTTP维护会话的方法并不多。可以使用带有 sessionId 的 cookie 或带有 sessionId 的标头。
如果有人有其他想法,我会很高兴听到。
我认为令牌必须包含其中编码的所有所需信息,这使得通过验证令牌和解码信息进行身份验证 https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/
不,使用会话并不一定违反 RESTfulness。如果您遵守 REST 规则和约束,那么使用会话(维护状态)将是多余的。毕竟,RESTfulness 要求服务器不维护状态。
评论
据我了解,当我们谈论会话时,有两种类型的状态
- 客户端和服务器交互状态
- 资源状态
这里的无状态约束是指 Rest 中的第二种类型。 使用 cookie(或本地存储)不会违反 Rest,因为它与第一种类型相关。
Fielding说:“从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。
这里的问题是,在服务器上要满足的每个请求都需要来自客户端的所有必要数据。然后,这被认为是无状态的。再说一遍,我们在这里谈论的不是 cookie,而是资源。
评论