How to enforce account based separation in Django

2020-02-26 02:43发布

I have a Django app which has a single-account model. We are converting this to be multi-account, so almost every model will have a ForeignKey(Account).

What is the easiest way to make sure that each Account (each account is in its own subdomain) can only access its own data? We have a middleware that populates the subdomain, and the current account on each request.

We can do this the hard way, by adding a filter(...., account = request.account) in all of our views. This is not desirable as,

  1. filter(...., account = request.account) will be added to all of the queries, making this non-dry, repetative and error-prone.
  2. Bigger risk is if there is a missing filter, anywhere it is security risk.

5条回答
时光不老,我们不散
2楼-- · 2020-02-26 02:55

Wow, I'm having the exact same problem. Here's the best answer I got:

Django: How would one organize this big model / manager / design mess?

查看更多
Animai°情兽
3楼-- · 2020-02-26 02:56

Are you using django.contrib.auth?

If you are, just make Account a ForeignKey(User, unique=true) and point all your models at User

ie. ForeignKey(User)

Also, Take a look at the django Auth Docs

edit: I think I understand your concern a little better now...

Instead of doing

my_model.objects.filter(user=request.user)

just do:

request.user.my_model_set.all()
查看更多
beautiful°
4楼-- · 2020-02-26 03:01

This snippet might put you in the right direction. I believe row level permissions are on the todo list for 1.2 also, not 100% sure on that one though.

查看更多
干净又极端
5楼-- · 2020-02-26 03:05

I don't think there is any clear winner, especially if you consider that not all queries will need to be filtered by account. Also consider the old threadlocals trick is considered unreliable which means the only way to do automatic insertion of filter parameters would be with middleware I guess... but that also seems unreliable and complex to me.

I also haven't come up with a good way to make a query manager that can help here, but it might be possible.

So, I think the best solution for a "multi-tenant" database is just to make sure all your queries are filtered by account. You can do this with:

  • Debug mode middleware such as Middleware: Record ownership screener

  • In your tests check the sql generated by any tests and verify the account field is in the query. You could also include "other account" data in your test fixtures that your test would make sure do not show up in any query results.

  • Making sure all queries are checked for the filter during code review

Certainly not pretty, but the best I've been able to do so far.

查看更多
霸刀☆藐视天下
6楼-- · 2020-02-26 03:06

Is there some huge reason why you can't just write a function that automatically inserts the session account into the query and takes all your other parameters as arguments?

查看更多
登录 后发表回答