简体   繁体   中英

Is using authentication as context RESTful?

I am wondering if implicitly using the currently authenticated user as context for API interactions is RESTful or not. For example, assuming all my API calls are authenticated using standard HTTP security:

Should a query to retrieve a list of orders for the user be explicit?
NO: http://example.com/orders
YES: http://example.com/orders?userid=1234

When placing a POST to create a new order, should the JSON contain the user?
NO: { orderref: 'EXAM/1', items: { ... } }
YES: { userid: 1234, orderref: 'EXAM/1', items: { ... } }

Either way I'll be securing so that the API will only allow actions for the current user, but should I make the API caller state the userid for each action?

I would say you should only pass the user ID as a query if you have access to many user's orders and need to filter them by user.

If a user has access to only their own orders they should not have to pass a user ID - the base queryset should limit it based on their own authentication details. Arguably that may not be RESTful, but don't worry about that - most API's may not be 100% RESTful and you should do what makes sense for your application rather than worrying about whether it's RESTful - it's a guide, not a cast-iron requirement.

In any case depending on what type of authentication you use (BASIC or TOKEN), you have to send the user info in your API call (Headers) which makes the request to the API.

So when you say if it is valid to use the authenticated user from the Context, of course it is

sample code here

The api call

headers.Authorization = 'Bearer ' + localStorage.getItem("tokenkey");

Obtain user from the request

RequestContext.Principal.Identity.Name

Is it RESTful? I would argue that: yes it is. There is no REST spec, so there's nothing really that says that it isn't. HTTP does allow this, and HTTP Caches should actually by default consider responses to GET requests with an Authorization header as private.

Should you use this design? I don't know! I think there's benefits to having per-user endpoints, because in the future it might allow User A to inspect the orders of User B.

In our API we actually have an example of an API similar to yours, but we do both.

  1. We have a /users/1234 endpoint.
  2. We also have a /current-user endpoint.

Initially the /current-user endpoint just redirected to the uri of the actual current user, but eventually we decided we're actually just going to return the full object without redirecting (due to browsers not behaving nicely with redirects).

The current-user endpoint does have a self link still that points to the real user resource.

So to sum it up. I think you are in the clear here, but I argue that there are strong design benefits to creating resources that have a consistent representation regardless of who's looking at it. It makes things a bit simpler and nicer.

And also don't forget that there's no reason why you can't, if you are actually following REST. All a client should care about is that there's a link somewhere to a list of orders and it shouldn't care what it's url is.

+1 for Matthew Daly's answer. Especially when the authenticated user has only access to his own orders (I assume that).

In case that your authenticated user can access more order lists than only his own, I would go like that:

/orders: the authenticated user's orders.
/orders/123: the specific user's orders.

If 123 equals the authenticated user's id - so what? It would be most likely no problem case for your client.

By designing a REST service you think of the comfort that the developers could have, when they use your API. I would say, this one is a comfortable solution.

Should a query to retrieve a list of orders for the user be explicit?
NO: http://example.com/orders
YES: http://example.com/orders?userid=1234

When placing a POST to create a new order, should the JSON contain the user?
NO: { orderref: 'EXAM/1', items: { ... } }
YES: { userid: 1234, orderref: 'EXAM/1', items: { ... } }

If user queries only its own orders, user id shouldn't be passed explicitly in the query - you should pass user token in HTTP header and your code should extract user id by provided token and determine whether authorized user has rights to see or modify particular data.

In case you want to let one user get or modify another user data then you would make additional endpoint - something like users/{userId}/orders or users/{userId}/orders/{orderId} . You would still pass user token via HTTP header and your implementation should check if user has admin rights for this action.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM