Rest API with multi-tenant database separated by c

2019-03-11 07:08发布

I have a multi-tenant database with the composite key

clientId - docId

The routing looks like this

/api/controller/clientId/docId

For authentication I use a "global" username such as an email + password, sent in the http-header of every request via https. The username maps explicitly to a client and is available on the backend.

What's the way to do it properly with rest and have best security?

  1. Route like above and just verify that the clientId according to the username is the same than in the routing

or

  1. Change the routing as below and get the clientId from a database before saving a record?

    /api/controller/docId

This may be an obvious question, but I'm worried about potential security issues. Or is it just a no-brainer to go with the shorter routing?

Thanks!

2条回答
唯我独甜
2楼-- · 2019-03-11 07:36

Mark's approach is completely valid, however, I happen to use /tenant/docid because each tenant has a different database. If you don't include tenant in the URI then it would be a real pain trying to decide which database to connect to and hunt for the document.

查看更多
Explosion°爆炸
3楼-- · 2019-03-11 07:39

I think /api/controller/docId is probably the best idea or a use a single surrogate key to represent ClientId and docId (my preference).

Unless you ever need to allow clients to view other clients resources I would hide it from the URI scheme, at worst it could be considered information leakage at best it is redundant as you have authenticated the client and know who they are anyway. It is also an overhead i.e. you still must check the client id in the url is mapped to the username and password of the request so you need to retrieve the client id on each request anyway.

If you looked at how other multi tenanted environments work e.g. Sales Force's you can see that they must infer the client via the security mechanism or are lucky enough to have a unique id for every object/resource.

An approach I have seen is to put the client identifier (usually a surrogate key of somekind, avoid exposing other users db id's!) at the root of the URL e.g. /api/{clientId}/controller/docId. In a multi tenanted environment every resource is probably/by definition unique to that client.

A reason sometimes given for this approach is that having a unique url per customer assists with caching... /api/{clientId}/controller/docId or /api/controller/{clientId}/docId

A brief note over basic authentication

Nothing wrong with your approach but consider... you could retrieve the client Id whilst validating the password and user name and add that as a claim on the IPrinciple. At least that is then available in the code without any further db look ups to find it (within the life of that request).

Going a step further... consider a two step authentication mechanism where a token is issued (following correct username and password) with the client Id actually in the token as a claim. This way, subsequent requests with the token mean you won't need to call back the the db for every request to authenticate and retrieve information. Take a look at OAuth bearer tokens http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html (be sure to sign them) or some of the other approaches...

查看更多
登录 后发表回答