ChatGPT解决这个技术问题 Extra ChatGPT

Do sessions really violate RESTfulness?

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?

To add to that, if you're only using the session for authentication, then why not use the provided headers? If not, and you're using the session for other state of the conversation, then that's violating the Stateless constraint of REST.
@Will Thanks. It seems you're talking about sessions for temporarily storing user submitted data, while in my case I'm just talking about them as an implementation detail for authentication. Might this be where the disagreement comes from?
@deceze My only point is that if you're going to use a header to represent an authentication token, HTTP provides one beyond a generic cookie. So, why not use that and keep the free semantics you get with it (anyone seeing the payload can see there's an authentication token assigned to it).
Sure, but then why not make up your own headers, or hijack some other header for the auth token. Use the X-XYZZY header. It's just syntax right? The headers convey information. The Authorization header is more "self-documenting" than your cookie is, because "everyone" know what the Auth header is for. If they just see JSESSIONID (or whatever), they can't make any assumptions, or worse, make the wrong assumptions (what else is he storing in the session, what else is this used for, etc.). Do you name your variables in your code Aq12hsg? No, of course not. Same thing applies here.

V
Val Entin

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.


I would rephrase your initial statement. Only use REST if the constraints of REST make sense of your application. You are free to apply a subset of those constraints and you will get a subset of the benefits. However, at that point you have created your own architectural style. That's not a bad thing though, in fact that's what the first four chapters of Roy's dissertation are about, principled design. REST was just one example.
@Jared Are you sure the Google auth token doesn't have the expiry date encoded into it? Doesn't seem like it would be two hard to do.
@Darrel A fair enough point. I'm honestly not sure how Google does it, but the expiration time could be encoded into the authentication token. I believe my larger point still stands though. There are some types of state that simply must be maintained and as long as you understand why REST calls for statelessness, you can violate it in a way that makes sense with out many repercussions on the rest of the system and the advantages of a RESTful architecture.
Since no other arguments have been made so far, I'm accepting this well written response. I think the important part is that stateless server does not mean stateless server, something that I think is often misunderstood or misapplied. The server may (and usually must) have any state it wants, as long as it behaves idempotent.
I've heard so much preaching that sessions are not restful. HTTP basic authentication is a real step backwards if you're trying to build a web app though.
M
Michał Ciuba

First, let's define some terms:

RESTful: One can characterise applications conforming to the REST constraints described in this section as "RESTful".[15] If a service violates any of the required constraints, it cannot be considered RESTful. according to wikipedia.

stateless constraint: We next add a constraint to the client-server interaction: communication must be stateless in nature, as in the client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3), such that 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. according to the Fielding dissertation.

So server side sessions violate the stateless constraint of REST, and so RESTfulness either.

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.

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.

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)

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:

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

Figure 1. - Stateless authentication by trusted clients

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:

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

Figure 2. - Stateless authentication by 3rd party clients

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.


Yes, you are completely right. Since I have posted this question I've totally come around to seeing that. Session cookies aren't anything special when looked at in the technical details, but that's missing the forest for the trees. Accepted your answer because of the nice charts. ;)
Ok, I rethought, the response of the REST service should not depend on the authorization, so I think the first 2 solutions are 100% okay, and the others are okay if the service uses the information only to decide whether it allows the request or not. So I think the user permissions should effect on the representation of the current resource.
I'll create a question about the permissions dependency of representations. I'll extend this answer as soon as I got the proper solution.
@inf3rno, it is true that a fully RESTful service cannot depend on session cookies for authentication in the way that it is traditionally implemented. However, you can use cookies to perform authentication if the cookie contains all the state information the server will later need. You can also make the cookie secure from tampering by signing it with a public/private key pair. See my comments below.
I don't understand why everyone seems to accept the comment you should store passwords on the client side and send them with every request. This is a very bad practice and endangers your customers sensitive data. An unhashed password (which it would have to be to send it over and over) should never be stored anywhere. If we accept this then you are using tokens as most authentication systems do, in which case whatever mechanism we use to scale the tokens repository will have mostly equal scalability concerns as any session scalability.
s
starteleport

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 that Set-Cookie is only a recommendation for client. Its contents may be or may not be saved (for example, if cookies are disabled), while Authorization 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:

You try GET /a without cookie

You get an authorization request somehow

You go and authorize somehow like POST /auth

You get Set-Cookie

You try GET /a with cookie. But does GET /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.


In the meantime I came around more to this point of view as well. I do think that technically it makes little difference, it's all just HTTP headers. It's true though that the authentication behavior itself is not RESTful, if login through a separate address is required. So cookies are only a symptom of a larger problem with the authentication system.
This doesn't really account for the fact that web browsers only support Authorization: Basic or Digest. If you want to do anything more advanced than basic or digest auth (and you should) in a browser context, then you're going to need something other than the Authorization header.
Absolutely - if you're doing pure JS then things are basically OK (except, for example, Websockets). But my point is that API-based auth isn't necessarily the only consideration in a browser scenario.
GET /a without a cookie and with a cookie are clearly two different requests, and it is acceptable for them to behave differently.
To add on to @TRiG, following this logic, GET /a with authentication header is also the same as GET /a without the authentication header, making it equally unusable for REST. If you're going to treat one http header differently from another, you're going to address that at the very least.
T
Tivie

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.


I don't see how this sheds any light on the question posed.
B
Bert Verhees

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.


A
Ahmet Firat Keler

As I understand, there are two types of state when we are talking about sessions

Client and Server Interaction State

Resource State

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.


M
Mohammad Tofic Mohammad

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/


u
user14699123

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.


In my opinion, the majority of the responses misunderstand what it means for an API to be RESTful. A RESTful API satisfies the REST constraints: Uniform Interface, Stateless, Cacheable, Client-Server, Layered System, Code on Demand. It is quite possible for your API to implement sessions while satisfying these constraints.
d
deceze

Sessions are not RESTless Do you mean that REST service for http-use only or I got smth wrong? Cookie-based session must be used only for own(!) http-based services! (It could be a problem to work with cookie, e.g. from Mobile/Console/Desktop/etc.) if you provide RESTful service for 3d party developers, never use cookie-based session, use tokens instead to avoid the problems with security.


the cookie should not be used to store a session key for a session on the server which holds the authentication token. but if the cookie holds the authentication token itself it's a feasible solution. (of course the cookie should be httponly and secured)