会话真的违反了 RESTful 原则吗?
在 RESTful API 中使用会话真的违反了 RESTful 原则吗?我见过很多不同方向的观点,但我不相信会话是RESTless。从我的角度来看:
- RESTful 并不禁止身份验证(否则在 RESTful 服务中几乎没有用处)
- 身份验证是通过在请求中发送身份验证令牌来完成的,通常
- 需要以某种方式获取此身份验证令牌的标头,并且可能是已撤销,在这种情况下需要更新身份
- 验证令牌需要由服务器验证(否则就不是身份验证)
那么会话如何违反这一点呢?
- 客户端,会话是使用 cookie 实现的
- cookie 只是一个额外的 HTTP 标头
- 可以随时获取和撤销会话 cookie
- 如果需要,会话 cookie 可以具有无限的生命周期
- 会话 id(身份验证令牌)在服务器端进行验证
因此,对于客户端来说,会话 cookie 与任何其他基于 HTTP 标头的身份验证机制完全相同,只是它使用 Cookie
标头而不是 Authorization
或某些内容。其他专有标头。如果服务器端没有附加到 cookie 值的会话,为什么会产生影响呢?只要服务器表现 RESTful,服务器端实现就不需要关心客户端。因此,cookie 本身不应该使 API RESTless,而会话对于客户端来说只是 cookie。
我的假设是错误的吗?是什么让会话cookieRESTless?
Is using sessions in a RESTful API really violating RESTfulness? I have seen many opinions going either direction, but I'm not convinced that sessions are RESTless. From my point of view:
- authentication is not prohibited for RESTfulness (otherwise there'd be little use in RESTful services)
- authentication is done by sending an authentication token in the request, usually the header
- this authentication token needs to be obtained somehow and may be revoked, in which case it needs to be renewed
- the authentication token needs to be validated by the server (otherwise it wouldn't be authentication)
So how do sessions violate this?
- client-side, sessions are realized using cookies
- cookies are simply an extra HTTP header
- a session cookie can be obtained and revoked at any time
- session cookies can have an infinite life time if need be
- the session id (authentication token) is validated server-side
As such, to the client, a session cookie is exactly the same as any other HTTP header based authentication mechanism, except that it uses the Cookie
header instead of the Authorization
or some other proprietary header. If there was no session attached to the cookie value server-side, why would that make a difference? The server side implementation does not need to concern the client as long as the server behaves RESTful. As such, cookies by themselves should not make an API RESTless, and sessions are simply cookies to the client.
Are my assumptions wrong? What makes session cookies RESTless?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
首先,REST 不是一种宗教,不应该被视为宗教。虽然 RESTful 服务有很多优点,但您应该只遵循 REST 的原则,只要它们对您的应用程序有意义。
也就是说,身份验证和客户端状态并不违反 REST 原则。虽然 REST 要求状态转换是无状态的,但这指的是服务器本身。从本质上讲,所有 REST 都与文档有关。无状态背后的想法是服务器是无状态的,而不是客户端。任何发出相同请求(相同标头、cookie、URI 等)的客户端都应被带到应用程序中的相同位置。如果网站存储用户的当前位置并通过更新此服务器端导航变量来管理导航,则将违反 REST。根据服务器端状态,具有相同请求信息的另一个客户端将被带到不同的位置。
Google 的网络服务是 RESTful 系统的绝佳示例。它们需要在每个请求时传递带有用户身份验证密钥的身份验证标头。这确实稍微违反了 REST 原则,因为服务器正在跟踪身份验证密钥的状态。必须维护此密钥的状态,并且它具有某种到期日期/时间,在此之后它不再授予访问权限。然而,正如我在帖子顶部提到的,必须做出牺牲才能让应用程序真正发挥作用。也就是说,身份验证令牌的存储方式必须允许所有可能的客户端在其有效时间内继续授予访问权限。如果一台服务器正在管理身份验证密钥的状态,以至于另一台负载平衡服务器无法接管基于该密钥的请求,那么您就已经开始真正违反 REST 原则。 Google 的服务可确保您随时获取您在手机上使用的针对负载平衡服务器 A 的身份验证令牌,并从您的桌面访问负载平衡服务器 B,并且仍然可以访问系统,并在以下情况下被定向到相同的资源:请求是相同的。
归根结底,您需要确保您的身份验证令牌针对某种类型的后备存储(数据库、缓存等)进行验证,以确保保留尽可能多的 REST 属性。
我希望这一切都是有道理的。您还应该查看 约束部分 en.wikipedia.org/wiki/Representational_state_transfer" rel="noreferrer">有关代表性状态转移的维基百科文章(如果您还没有阅读过)。对于 REST 的原则实际上主张什么以及为什么主张,它特别具有启发性。
First of all, REST is not a religion and should not be approached as such. While there are advantages to RESTful services, you should only follow the tenets of REST as far as they make sense for your application.
That said, authentication and client side state do not violate REST principles. While REST requires that state transitions be stateless, this is referring to the server itself. At the heart, all of REST is about documents. The idea behind statelessness is that the SERVER is stateless, not the clients. Any client issuing an identical request (same headers, cookies, URI, etc) should be taken to the same place in the application. If the website stored the current location of the user and managed navigation by updating this server side navigation variable, then REST would be violated. Another client with identical request information would be taken to a different location depending on the server-side state.
Google's web services are a fantastic example of a RESTful system. They require an authentication header with the user's authentication key to be passed upon every request. This does violate REST principles slightly, because the server is tracking the state of the authentication key. The state of this key must be maintained and it has some sort of expiration date/time after which it no longer grants access. However, as I mentioned at the top of my post, sacrifices must be made to allow an application to actually work. That said, authentication tokens must be stored in a way that allows all possible clients to continue granting access during their valid times. If one server is managing the state of the authentication key to the point that another load balanced server cannot take over fulfilling requests based on that key, you have started to really violate the principles of REST. Google's services ensure that, at any time, you can take an authentication token you were using on your phone against load balance server A and hit load balance server B from your desktop and still have access to the system and be directed to the same resources if the requests were identical.
What it all boils down to is that you need to make sure your authentication tokens are validated against a backing store of some sort (database, cache, whatever) to ensure that you preserve as many of the REST properties as possible.
I hope all of that made sense. You should also check out the Constraints section of the wikipedia article on Representational State Transfer if you haven't already. It is particularly enlightening with regard to what the tenets of REST are actually arguing for and why.
首先,让我们定义一些术语:
RESTful:
<块引用>
可以表征符合 REST 约束的应用程序
本节中描述为“RESTful”。[15]如果某项服务违反了任何
所需的约束,它不能被视为 RESTful。
根据维基百科。
无状态约束:
<块引用>
接下来我们向客户端-服务器交互添加约束:
通信本质上必须是无状态的,如
第 3.4.3 节的客户端-无状态-服务器 (CSS) 样式(图 5-3),
这样从客户端到服务器的每个请求都必须包含所有
理解请求所必需的信息,并且不能采取
利用服务器上任何存储的上下文。会话状态是
因此完全保留在客户端上。
根据Fielding论文。< /p>
因此,服务器端会话违反了 REST 的无状态约束,因此也违反了 REST 性。
通过会话 cookie,您可以将客户端状态存储在服务器上,因此您的请求具有上下文。让我们尝试向您的系统添加一个负载均衡器和另一个服务实例。在这种情况下,您必须在服务实例之间共享会话。这样的系统很难维护和扩展,因此扩展性很差……
在我看来,cookie 没有什么问题。 cookie 技术是一种客户端存储机制,其中存储的数据通过每个请求自动附加到 cookie 标头。我不知道 REST 约束对这种技术有问题。所以技术本身没有问题,问题在于它的使用。 菲尔丁写了一个小节解释他的想法HTTP cookies 是不好的。
您的观点非常可靠。唯一的问题是在服务器上创建身份验证令牌的概念。你不需要那部分。您需要的是将用户名和密码存储在客户端上,并在每次请求时发送。除了 HTTP 基本身份验证和加密连接之外,您不需要更多内容即可执行此操作:
您可能需要服务器端的内存中身份验证缓存来加快速度,因为您必须对每个请求进行身份验证。
现在,这对于您编写的值得信赖的客户端来说效果很好,但是第 3 方客户端呢?他们无法拥有用户名和密码以及用户的所有权限。因此,您必须单独存储特定用户可以拥有第三方客户端的权限。因此,客户端开发人员可以注册他们的第 3 方客户端,并获得唯一的 API 密钥,并且用户可以允许第 3 方客户端访问其部分权限。例如读取姓名和电子邮件地址,或列出他们的朋友等...允许第 3 方客户端后,服务器将生成访问令牌。第三方客户端可以使用这些访问令牌来访问用户授予的权限,如下所示:
因此,第 3 方客户端可以从受信任的客户端(或直接从用户)获取访问令牌。之后,它可以使用 API 密钥和访问令牌发送有效请求。这是最基本的第三方身份验证机制。您可以在每个第 3 方身份验证系统(例如 OAuth)的文档中阅读有关实施细节的更多信息。当然,这可能更复杂、更安全,例如您可以在服务器端对每个请求的详细信息进行签名,然后将签名与请求一起发送,等等……实际的解决方案取决于您的应用程序的需求。
First, let's define some terms:
RESTful:
according to wikipedia.
stateless constraint:
according to the Fielding dissertation.
So server side sessions violate the stateless constraint of REST, and so RESTfulness either.
By session cookies you store the client state on the server and so your request has a context. Let's try to add a load balancer and another service instance to your system. In this case you have to share the sessions between the service instances. It is hard to maintain and extend such a system, so it scales badly...
In my opinion there is nothing wrong with cookies. The cookie technology is a client side storing mechanism in where the stored data is attached automatically to cookie headers by every request. I don't know of a REST constraint which has problem with that kind of technology. So there is no problem with the technology itself, the problem is with its usage. Fielding wrote a sub-section about why he thinks HTTP cookies are bad.
Your point of view was pretty solid. The only problem was with the concept of creating authentication token on the server. You don't need that part. What you need is storing username and password on the client and send it with every request. You don't need more to do this than HTTP basic auth and an encrypted connection:
You probably need an in-memory auth cache on server side to make things faster, since you have to authenticate every request.
Now this works pretty well by trusted clients written by you, but what about 3rd party clients? They cannot have the username and password and all the permissions of the users. So you have to store separately what permissions a 3rd party client can have by a specific user. So the client developers can register they 3rd party clients, and get an unique API key and the users can allow 3rd party clients to access some part of their permissions. Like reading the name and email address, or listing their friends, etc... After allowing a 3rd party client the server will generate an access token. These access token can be used by the 3rd party client to access the permissions granted by the user, like so:
So the 3rd party client can get the access token from a trusted client (or directly from the user). After that it can send a valid request with the API key and access token. This is the most basic 3rd party auth mechanism. You can read more about the implementation details in the documentation of every 3rd party auth system, e.g. OAuth. Of course this can be more complex and more secure, for example you can sign the details of every single request on server side and send the signature along with the request, and so on... The actual solution depends on your application's need.
Cookie 不用于身份验证。为什么要重新发明轮子? HTTP 具有设计良好的身份验证机制。如果我们使用cookie,我们就会陷入仅使用HTTP作为传输协议的情况,因此我们需要创建我们自己的信号系统,例如,告诉用户他们提供了错误的身份验证(使用HTTP 401将是不正确,因为我们可能不会按照 HTTP 规范的要求向客户端提供
Www-Authenticate
:) )。还应该注意的是,Set-Cookie
只是对客户端的推荐。其内容可能会或可能不会被保存(例如,如果禁用 cookie),而Authorization
标头会在每次请求时自动发送。另一点是,要获取授权 cookie,您可能需要首先在某处提供您的凭据?如果是这样的话,那岂不是心神不宁了?简单的例子:
GET /a
POST /auth
Set-Cookie
GET /a
。但是在这种情况下GET /a
的行为是否幂等呢?总而言之,我相信如果我们访问某些资源并且需要进行身份验证,那么我们必须在同一资源上进行身份验证,而不是在其他任何地方进行身份验证。
Cookies are not for authentication. Why reinvent a wheel? HTTP has well-designed authentication mechanisms. If we use cookies, we fall into using HTTP as a transport protocol only, thus we need to create our own signaling system, for example, to tell users that they supplied wrong authentication (using HTTP 401 would be incorrect as we probably wouldn't supply
Www-Authenticate
to a client, as HTTP specs require :) ). It should also be noted thatSet-Cookie
is only a recommendation for client. Its contents may be or may not be saved (for example, if cookies are disabled), whileAuthorization
header is sent automatically on every request.Another point is that, to obtain an authorization cookie, you'll probably want to supply your credentials somewhere first? If so, then wouldn't it be RESTless? Simple example:
GET /a
without cookiePOST /auth
Set-Cookie
GET /a
with cookie. But doesGET /a
behave idempotently in this case?To sum this up, I believe that if we access some resource and we need to authenticate, then we must authenticate on that same resource, not anywhere else.
实际上,RESTful 仅适用于资源,如通用资源标识符所示。因此,甚至谈论 REST 中的 headers、cookies 等内容也是不太合适的。 REST 可以在任何协议上工作,即使它通常是通过 HTTP 完成的。
主要决定因素是这样的:如果您发送一个 REST 调用(它是一个 URI),那么一旦该调用成功到达服务器,该 URI 是否会返回相同的内容(假设未执行任何转换(PUT、POST、DELETE)) ?此测试将排除返回的错误或身份验证请求,因为在这种情况下,请求尚未发送到服务器,这意味着 servlet 或应用程序将返回与给定 URI 相对应的文档。
同样,在 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 还是标头来完成,只要该信息不是 URI 和 POST 有效负载的一部分,它确实是有效的。与 REST 完全无关,因此,关于无状态,我们仅讨论应用程序数据,
例如,当用户将数据输入 GUI 屏幕时,客户端会跟踪已输入的字段 。 ,其中没有,缺少任何必需的字段等。这都是客户端上下文,不应由服务器发送或跟踪。发送到服务器的是需要在客户端中修改的完整字段集。已识别资源(通过 URI),以便该资源发生从一种 RESTful 状态到另一种状态的转换,
因此,客户端会跟踪用户正在执行的操作,并且仅将逻辑上完整的状态转换发送到服务器。
Actually, RESTfulness only applies to RESOURCES, as indicated by a Universal Resource Identifier. So to even talk about things like headers, cookies, etc. in regards to REST is not really appropriate. REST can work over any protocol, even though it happens to be routinely done over HTTP.
The main determiner is this: if you send a REST call, which is a URI, then once the call makes it successfully to the server, does that URI return the same content, assuming no transitions have been performed (PUT, POST, DELETE)? This test would exclude errors or authentication requests being returned, because in that case, the request has not yet made it to the server, meaning the servlet or application that will return the document corresponding to the given URI.
Likewise, in the case of a POST or PUT, can you send a given URI/payload, and regardless of how many times you send the message, it will always update the same data, so that subsequent GETs will return a consistent result?
REST is about the application data, not about the low-level information required to get that data transferred about.
In the following blog post, Roy Fielding gave a nice summary of the whole REST idea:
http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841
"A RESTful system progresses from one steady-state to the
next, and each such steady-state is both a potential start-state
and a potential end-state. I.e., a RESTful system is an unknown
number of components obeying a simple set of rules such that they
are always either at REST or transitioning from one RESTful
state to another RESTful state. Each state can be completely
understood by the representation(s) it contains and the set of
transitions that it provides, with the transitions limited to a
uniform set of actions to be understandable. The system may be
a complex state diagram, but each user agent is only able to see
one state at a time (the current steady-state) and thus each
state is simple and can be analyzed independently. A user, OTOH,
is able to create their own transitions at any time (e.g., enter
a URL, select a bookmark, open an editor, etc.)."
Going to the issue of authentication, whether it is accomplished through cookies or headers, as long as the information isn't part of the URI and POST payload, it really has nothing to do with REST at all. So, in regards to being stateless, we are talking about the application data only.
For example, as the user enters data into a GUI screen, the client is keeping track of what fields have been entered, which have not, any required fields that are missing etc. This is all CLIENT CONTEXT, and should not be sent or tracked by the server. What does get sent to the server is the complete set of fields that need to be modified in the IDENTIFIED resource (by the URI), such that a transition occurs in that resource from one RESTful state to another.
So, the client keeps track of what the user is doing, and only sends logically complete state transitions to the server.
据我了解,当我们谈论会话时,有两种类型的状态
无状态约束这里指的是Rest中的第二种类型。使用cookie(或本地存储)并不违反Rest,因为它与第一个相关。
Fielding 说:“从客户端到服务器的每个请求都必须包含理解该请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。
这里的问题是,服务器上要满足的每个请求都需要来自客户端的所有必要数据。那么这就被认为是无状态的。再次强调,我们这里讨论的不是 cookie,而是资源。
As I understand, there are two types of state when we are talking about sessions
Stateless constraint here refers to the second type in Rest. Using cookies (or local storage) does not violate Rest since it is related to the first.
Fielding says: 'Each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.'
The thing here is that every request to be fulfilled on the server needs the all necessary data from the client. Then this is considered as stateless. And again, we're not talking about cookies here, we're talking about resources.
HTTP事务,基本访问认证,不适合RBAC,因为基本访问认证每次都使用加密的用户名:密码来进行识别,而RBAC中需要的是用户想要用于特定调用的Role。
RBAC 不验证用户名的权限,而是验证角色的权限。
您可以尝试像这样连接:usernameRole:password,但这是不好的做法,而且效率也很低,因为当用户拥有更多角色时,身份验证引擎需要测试连接中的所有角色,并且每次调用都需要再次测试。这将破坏 RBAC 最大的技术优势之一,即非常快速的授权测试。
因此,使用基本访问身份验证无法解决该问题。
为了解决这个问题,会话维护是必要的,根据一些答案,这似乎与 REST 相矛盾。
这就是我喜欢“休息不应该被视为一种宗教”这个答案的原因。在复杂的业务案例中,例如在医疗保健领域,RBAC 绝对是常见且必要的。如果他们不被允许使用 REST,那将是一件遗憾的事,因为所有 REST 工具的设计者都会将 REST 视为一种宗教。
对我来说,通过 HTTP 维护会话的方法并不多。可以使用带有 sessionId 的 cookie 或带有 sessionId 的标头。
如果有人有其他想法,我会很高兴听到。
HTTP transaction, basic access authentication, is not suitable for RBAC, because basic access authentication uses the encrypted username:password every time to identify, while what is needed in RBAC is the Role the user wants to use for a specific call.
RBAC does not validate permissions on username, but on roles.
You could tric around to concatenate like this: usernameRole:password, but this is bad practice, and it is also inefficient because when a user has more roles, the authentication engine would need to test all roles in concatenation, and that every call again. This would destroy one of the biggest technical advantages of RBAC, namely a very quick authorization-test.
So that problem cannot be solved using basic access authentication.
To solve this problem, session-maintaining is necessary, and that seems, according to some answers, in contradiction with REST.
That is what I like about the answer that REST should not be treated as a religion. In complex business cases, in healthcare, for example, RBAC is absolutely common and necessary. And it would be a pity if they would not be allowed to use REST because all REST-tools designers would treat REST as a religion.
For me there are not many ways to maintain a session over HTTP. One can use cookies, with a sessionId, or a header with a sessionId.
If someone has another idea I will be glad to hear it.
我认为令牌必须包含其内部编码的所有需要的信息,这通过验证令牌和解码信息来进行身份验证
https://www.oauth.com/oauth2 -服务器/访问令牌/自编码访问令牌/
i think token must include all the needed information encoded inside it, which makes authentication by validating the token and decoding the info
https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/
不,使用会话并不一定违反 RESTful。如果您遵守 REST 规则和约束,那么使用会话(来维护状态)将是多余的。毕竟,RESTful 要求服务器不维护状态。
No, using sessions does not necessarily violate RESTfulness. If you adhere to the REST precepts and constraints, then using sessions - to maintain state - will simply be superfluous. After all, RESTfulness requires that the server not maintain state.