ChatGPT解决这个技术问题 Extra ChatGPT

会话真的违反了 RESTfulness 吗?

在 RESTful API 中使用会话真的违反了 RESTful 吗?我已经看到很多意见都朝着这两个方向发展,但我不相信会话是 RESTless 的。在我看来,我的观点是:

RESTful 不禁止身份验证(否则在 RESTful 服务中几乎没有用处)

身份验证是通过在请求中发送身份验证令牌来完成的,通常是标头

此身份验证令牌需要以某种方式获得并且可能被撤销,在这种情况下需要更新

身份验证令牌需要由服务器验证(否则它不会是身份验证)

那么会话如何违反这一点?

客户端,使用cookies实现会话

cookie 只是一个额外的 HTTP 标头

可以随时获取和撤销会话 cookie

如果需要,会话 cookie 可以有无限的生命周期

会话 ID(身份验证令牌)在服务器端进行验证

因此,对于客户端而言,会话 cookie 与任何其他基于 HTTP 标头的身份验证机制完全相同,只是它使用 Cookie 标头而不是 Authorization 或其他一些专有标头。如果没有会话附加到 cookie 值服务器端,为什么会有所不同?只要服务器表现 RESTful,服务器端实现就不需要关心客户端。因此,cookie 本身不应构成 APIRESTless,会话只是客户端的 cookie。

我的假设是错误的吗?是什么让会话 cookie 无 REST?

我在这里讨论了这个确切的问题:stackoverflow.com/questions/1296421/rest-complex-applications/…
除此之外,如果您只使用会话进行身份验证,那么为什么不使用提供的标头呢?如果不是,并且您将会话用于会话的其他状态,那么这违反了 REST 的无状态约束。
@威尔谢谢。您似乎在谈论用于临时存储用户提交数据的会话,而在我的情况下,我只是在谈论它们作为身份验证的实现细节。这可能是分歧的来源吗?
@deceze 我唯一的一点是,如果您要使用标头来表示身份验证令牌,HTTP 提供了一个超越通用 cookie 的标头。那么,为什么不使用它并保留您获得的免费语义(任何看到有效负载的人都可以看到分配给它的身份验证令牌)。
当然可以,但是为什么不制作自己的标头,或者为身份验证令牌劫持其他标头。使用 X-XYZZY 标题。这只是语法对吗?标头传达信息。 Authorization 标头比您的 cookie 更“自我记录”,因为“每个人”都知道 Auth 标头的用途。如果他们只看到 JSESSIONID(或其他),他们就无法做出任何假设,或者更糟糕的是,做出错误的假设(他在会话中还存储了什么,它还有什么用途等)。您是否在代码 Aq12hsg 中命名变量?不,当然不是。同样的事情也适用于此。

V
Val Entin

首先,REST 不是一种宗教,不应该这样对待。尽管 RESTful 服务有很多优点,但您应该只遵循 REST 的原则,只要它们对您的应用程序有意义。

也就是说,身份验证和客户端状态不违反 REST 原则。虽然 REST 要求状态转换是无状态的,但这是指服务器本身。从本质上讲,所有 REST 都是关于文档的。无状态背后的想法是服务器是无状态的,而不是客户端。任何发出相同请求(相同的标头、cookie、URI 等)的客户端都应该被带到应用程序中的相同位置。如果网站存储了用户的当前位置并通过更新此服务器端导航变量来管理导航,那么将违反 REST。根据服务器端的状态,具有相同请求信息的另一个客户端将被带到不同的位置。

Google 的 Web 服务是 RESTful 系统的绝佳示例。它们需要一个带有用户身份验证密钥的身份验证标头,以便在每个请求时传递。这确实稍微违反了 REST 原则,因为服务器正在跟踪身份验证密钥的状态。必须维护此密钥的状态,并且它具有某种到期日期/时间,在此之后它不再授予访问权限。然而,正如我在帖子顶部提到的,必须做出牺牲才能让应用程序真正工作。也就是说,身份验证令牌的存储方式必须允许所有可能的客户端在其有效时间内继续授予访问权限。如果一台服务器正在管理身份验证密钥的状态,以至于另一台负载平衡服务器无法接管基于该密钥的请求,那么您已经开始真正违反 REST 的原则。 Google 的服务可确保您在任何时候都可以将您在手机上使用的身份验证令牌用于负载平衡服务器 A,并从您的桌面访问负载平衡服务器 B,并且仍然可以访问系统并被定向到相同的资源,如果请求是相同的。

归根结底,您需要确保您的身份验证令牌已针对某种类型的后备存储(数据库、缓存等)进行验证,以确保您保留尽可能多的 REST 属性。

我希望所有这些都是有道理的。如果您还没有查看 wikipedia article on Representational State TransferConstraints section,您还应该查看。关于 REST 的原则实际上在争论什么以及为什么争论,这尤其具有启发性。


我会改写你最初的陈述。仅当 REST 的约束对您的应用程序有意义时才使用 REST。您可以自由地应用这些约束的一个子集,并且您将获得一部分好处。但是,此时您已经创建了自己的建筑风格。不过这并不是一件坏事,事实上这就是 Roy 论文的前四章的内容,即原则性设计。 REST 只是一个例子。
@Jared 您确定 Google 身份验证令牌中没有编码到期日期吗?看起来这两个都不是很难做到的。
@Darrel 一个足够公平的观点。老实说,我不确定 Google 是如何做到的,但可以将过期时间编码到身份验证令牌中。我相信我更大的观点仍然存在。有一些类型的状态是必须维护的,只要你理解为什么 REST 要求无状态,你可以以一种有意义的方式违反它,而不会对系统的其余部分产生很多影响以及 RESTful 架构的优势.
由于到目前为止还没有提出其他论点,我接受了这个写得很好的回应。我认为重要的部分是无状态服务器并不意味着无状态服务器,我认为这经常被误解或误用。服务器可能(并且通常必须)具有它想要的任何状态,只要它表现出幂等性。
我听了太多的讲道,以至于会议并不平静。但是,如果您尝试构建 Web 应用程序,HTTP 基本身份验证是一个真正的倒退。
M
Michał Ciuba

首先,让我们定义一些术语:

RESTful:可以将符合本节中描述的 REST 约束的应用程序描述为“RESTful”。 [15]如果服务违反了任何必需的约束,则不能将其视为 RESTful。根据维基百科。

无状态约束:我们接下来为客户端-服务器交互添加一个约束:通信本质上必须是无状态的,如第 3.4.3 节(图 5-3)的客户端-无状态-服务器(CSS)样式中,这样每个请求从客户端到服务器必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。根据菲尔丁论文。

因此,服务器端会话违反了 REST 的无状态约束,因此 RESTful 也是如此。

因此,对于客户端而言,会话 cookie 与任何其他基于 HTTP 标头的身份验证机制完全相同,只是它使用 Cookie 标头而不是 Authorization 或其他一些专有标头。

通过会话 cookie,您将客户端状态存储在服务器上,因此您的请求具有上下文。让我们尝试将负载均衡器和另一个服务实例添加到您的系统。在这种情况下,您必须在服务实例之间共享会话。很难维护和扩展这样的系统,所以它的扩展性很差......

在我看来,cookie 没有任何问题。 cookie 技术是一种客户端存储机制,其中存储的数据通过每个请求自动附加到 cookie 标头。我不知道这种技术存在问题的 REST 约束。所以技术本身没有问题,问题在于它的使用。 Fielding wrote a sub-section 关于他认为 HTTP cookie 不好的原因。

从我的角度来看:RESTful 不禁止身份验证(否则在 RESTful 服务中几乎没有用处)身份验证是通过在请求中发送身份验证令牌来完成的,通常需要以某种方式获取此身份验证令牌的标头,并且可能是已撤销,在这种情况下需要更新身份验证令牌需要由服务器验证(否则它不会是身份验证)

你的观点很中肯。唯一的问题是在服务器上创建身份验证令牌的概念。你不需要那部分。您需要将用户名和密码存储在客户端上,并随每个请求一起发送。除了 HTTP 基本身份验证和加密连接之外,您不需要做更多的事情:

https://i.stack.imgur.com/9kiTW.png

图 1. - 受信任客户端的无状态身份验证

您可能需要在服务器端使用内存中的身份验证缓存来加快速度,因为您必须对每个请求进行身份验证。

现在,您编写的受信任的客户可以很好地工作,但是第 3 方客户呢?他们不能拥有用户名和密码以及用户的所有权限。因此,您必须单独存储特定用户可以拥有的 3rd 方客户端的权限。因此客户端开发者可以注册他们的第 3 方客户端,并获得一个唯一的 API 密钥,并且用户可以允许第 3 方客户端访问他们的部分权限。比如读取姓名和电子邮件地址,或者列出他们的朋友等等……在允许第三方客户端之后,服务器将生成一个访问令牌。第三方客户端可以使用这些访问令牌来访问用户授予的权限,如下所示:

https://i.stack.imgur.com/HeG0r.png

图 2. - 第三方客户端的无状态身份验证

因此,第 3 方客户端可以从受信任的客户端(或直接从用户)获取访问令牌。之后,它可以使用 API 密钥和访问令牌发送有效请求。这是最基本的 3rd 方身份验证机制。您可以在每个 3rd 方身份验证系统(例如 OAuth)的文档中阅读有关实施细节的更多信息。当然,这可能更复杂,更安全,例如您可以在服务器端签署每个请求的详细信息,然后将签名与请求一起发送,等等......实际的解决方案取决于您的应用程序的需要。


是的,你完全正确。自从我发布了这个问题以来,我已经完全看到了这一点。从技术细节来看,会话 cookie 并没有什么特别之处,但这就是只见树木不见森林。由于漂亮的图表,接受了您的答案。 ;)
好的,我重新考虑,REST服务的响应不应该依赖于授权,所以我认为前2个解决方案是100%可以的,其他的如果服务只使用信息来决定它是否允许请求还是可以的不是。所以我认为用户权限应该影响当前资源的表示。
我将创建一个关于表示的权限依赖性的问题。得到正确的解决方案后,我将立即扩展此答案。
@inf3rno,确实,完全 RESTful 服务不能像传统实现方式那样依赖会话 cookie 进行身份验证。但是,如果 cookie 包含服务器稍后需要的所有状态信息,则可以使用 cookie 执行身份验证。您还可以通过使用公钥/私钥对对其进行签名来确保 cookie 免受篡改。请参阅下面的评论。
我不明白为什么每个人似乎都接受你应该在客户端存储密码并在每个请求中发送它们的评论。这是一种非常糟糕的做法,会危及您的客户敏感数据。未散列的密码(必须一遍又一遍地发送)永远不应该存储在任何地方。如果我们接受这一点,那么您将像大多数身份验证系统一样使用令牌,在这种情况下,我们用于扩展令牌存储库的任何机制都将具有与任何会话可扩展性大致相同的可扩展性问题。
s
starteleport

Cookie 不用于身份验证。为什么要重新发明轮子? HTTP 具有精心设计的身份验证机制。如果我们使用 cookie,我们就会陷入只使用 HTTP 作为传输协议,因此我们需要创建自己的自己的信号系统,例如,告诉用户他们提供了错误的身份验证(使用 HTTP 401 会不正确,因为我们可能不会向客户端提供 Www-Authenticate,因为 HTTP 规范要求 :) )。还应该注意的是,Set-Cookie 只是对客户的建议。它的内容可能会被保存,也可能不会被保存(例如,如果 cookie 被禁用),而 Authorization 标头会在每次请求时自动发送。

另一点是,要获得授权 cookie,您可能想先在某处提供您的凭据?如果是这样,那不是 RESTless 吗?简单的例子:

你尝试 GET /a 没有 cookie

您以某种方式收到授权请求

你去以某种方式授权,比如 POST /auth

你得到 Set-Cookie

您尝试 GET /a 与 cookie。但是在这种情况下 GET /a 是否具有幂等性?

总而言之,我相信如果我们访问某个资源并且我们需要进行身份验证,那么我们必须在同一资源上进行身份验证,而不是在其他任何地方进行身份验证。


与此同时,我也更多地转向了这个观点。我确实认为从技术上讲它没有什么区别,这只是 HTTP 标头。确实,如果需要通过单独的地址登录,身份验证行为本身不是 RESTful。因此 cookie 只是身份验证系统存在较大问题的一个症状。
这并不能真正说明 Web 浏览器仅支持 Authorization: BasicDigest 的事实。如果您想在浏览器上下文中执行比基本身份验证或摘要身份验证更高级的操作(并且您应该),那么您将需要除 Authorization 标头之外的其他内容。
绝对 - 如果您正在做纯 JS,那么事情基本上没问题(例如,Websockets 除外)。但我的观点是,基于 API 的身份验证不一定是浏览器场景中唯一的考虑因素。
GET /a 没有 cookie 和有 cookie 显然是两个不同的请求,它们的行为不同是可以接受的。
要添加到 @TRiG,遵循此逻辑,带有身份验证标头的 GET /a 也与没有身份验证标头的 GET /a 相同,因此同样无法用于 REST。如果您打算以不同的方式处理一个 http 标头,那么您至少要解决这个问题。
T
Tivie

实际上,RESTful 仅适用于 RESOURCES,如通用资源标识符所示。因此,甚至谈论关于 REST 的标头、cookie 等内容是不合适的。 REST 可以在任何协议上工作,即使它恰好是通过 HTTP 常规完成的。

主要决定因素是这样的:如果您发送一个 REST 调用,它是一个 URI,那么一旦调用成功到达服务器,该 URI 是否返回相同的内容,假设没有执行转换(PUT、POST、DELETE) ?此测试将排除错误或返回的身份验证请求,因为在这种情况下,请求尚未到达服务器,这意味着将返回与给定 URI 对应的文档的 servlet 或应用程序。

同样,在 POST 或 PUT 的情况下,您是否可以发送给定的 URI/payload,并且无论您发送多少次消息,它总是会更新相同的数据,以便后续 GET 将返回一致的结果?

REST 是关于应用程序数据的,而不是关于传输该数据所需的低级信息。

在下面的博客文章中,Roy Fielding 对整个 REST 理念进行了很好的总结:

http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841

“一个 RESTful 系统从一个稳态发展到下一个稳态,每个这样的稳态既是一个潜在的开始状态,也是一个潜在的结束状态。也就是说,一个 RESTful 系统是未知数量的组件,它们服从一组简单的规则使得它们总是处于 REST 状态或从一个 RESTful 状态转换到另一个 RESTful 状态。每个状态都可以通过它包含的表示和它提供的一组转换来完全理解,并且转换限制为统一的一组动作是可以理解的。系统可能是一个复杂的状态图,但每个用户代理一次只能看到一个状态(当前稳态),因此每个状态都很简单,可以独立分析。用户 OTOH 可以随时创建自己的转换(例如,输入 URL、选择书签、打开编辑器等)。”

转到身份验证问题,无论是通过 cookie 还是 headers 来完成,只要信息不是 URI 和 POST 有效负载的一部分,它就与 REST 完全无关。因此,关于无状态,我们只讨论应用程序数据。

例如,当用户在 GUI 屏幕中输入数据时,客户端会跟踪已输入的字段、未输入的字段、缺少的任何必填字段等。这都是 CLIENT CONTEXT,不应发送或跟踪由服务器。发送到服务器的是需要在 IDENTIFIED 资源中修改的完整字段集(通过 URI),以便在该资源中发生从一种 RESTful 状态到另一种状态的转换。

因此,客户端会跟踪用户正在做什么,并且只会将逻辑上完整的状态转换发送到服务器。


我看不出这如何阐明所提出的问题。
B
Bert Verhees

HTTP事务,基本访问认证,不适合RBAC,因为基本访问认证每次都使用加密后的username:password来识别,而RBAC中需要的是用户想要用于特定调用的角色。 RBAC 不会验证用户名的权限,而是验证角色的权限。

您可以像这样尝试连接:usernameRole:password,但这是不好的做法,而且效率也很低,因为当用户拥有更多角色时,身份验证引擎需要测试连接中的所有角色,并且每次调用都需要再次测试。这将破坏 RBAC 的最大技术优势之一,即非常快速的授权测试。

因此,使用基本访问身份验证无法解决该问题。

为了解决这个问题,会话维护是必要的,根据一些答案,这似乎与 REST 相矛盾。

这就是我喜欢 REST 不应被视为一种宗教的答案。在复杂的业务案例中,例如在医疗保健领域,RBAC 绝对是常见且必要的。如果不允许他们使用 REST,那就太可惜了,因为所有 REST 工具的设计者都将 REST 视为一种宗教。

对我来说,通过 HTTP 维护会话的方法并不多。可以使用带有 sessionId 的 cookie 或带有 sessionId 的标头。

如果有人有其他想法,我会很高兴听到它。


A
Ahmet Firat Keler

据我了解,当我们谈论会话时,有两种状态

客户端和服务器交互状态

资源状态

这里的无状态约束是指Rest中的第二种类型。使用 cookie(或本地存储)不会违反 Rest,因为它与第一个有关。

菲尔丁说:“从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。

这里的问题是,要在服务器上完成的每个请求都需要来自客户端的所有必要数据。那么这被认为是无状态的。再说一次,我们在这里不是在谈论 cookie,而是在谈论资源。


M
Mohammad Tofic Mohammad

我认为令牌必须包含其中编码的所有需要的信息,这通过验证令牌和解码信息来进行身份验证https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/


u
user14699123

不,使用会话不一定违反 RESTful。如果您遵守 REST 规则和约束,那么使用会话(维护状态)将是多余的。毕竟,RESTful 要求服务器不维护状态。


在我看来,大多数回复都误解了 API 是 RESTful 的含义。 RESTful API 满足 REST 约束:统一接口、无状态、可缓存、客户端-服务器、分层系统、按需代码。您的 API 很有可能在满足这些约束的同时实现会话。
d
deceze

会话不是 RESTless 您的意思是 REST 服务仅用于 http 还是我弄错了?基于 Cookie 的会话只能用于自己的(!)基于 http 的服务! (使用 cookie 可能会出现问题,例如来自 Mobile/Console/Desktop/etc。)如果您为 3d 方开发人员提供 RESTful 服务,请不要使用基于 cookie 的会话,而是使用令牌来避免安全问题。


cookie 不应该用于在保存身份验证令牌的服务器上存储会话的会话密钥。但如果 cookie 本身持有身份验证令牌,这是一个可行的解决方案。 (当然 cookie 应该是 httponly 和安全的)