0đź‘Ť
When you’re using Django auth
, always rely on the session
mechanism to identify an user instead of making some other id such as uuid1()
(except, for example, when you need extra sessions in an e-commerce site under HTTPS
).
For the permission part, you could check the ownership directly, mainly as described by Koliber Services. The relationships between Company
, User
and Contact
are crucial for the logic of permission checking. There are many ways to model the relationships and thus the code would differ much. For example:
# a modeling way
User.company -> Company : an user belongs to a company
Contact.contributor -> User : a contact is contributed by an user, would be invalid is user is leaving the company
# could check accessibility by
can_view = contact.contributor.company_id == current_user.company_id
# another modeling way
User.company -> Company : an user belongs to a company
Contact.company -> Company : a contact info is owned by a company, does not share globally
# could check accessibility by
can_view = contact.company_id == current_user.company_id
When can_view
is False
, user should get a 403 for his unauthorized attempting and get logged.
Normally the above method is enough for content protection(not yet in Django Admin). However, when you have many different types of permission checking and even row-permission checkings, it’s better to use some uniform permission API.
Take Django-guardian for example, you could simply map companies to groups and assign
can_view
permission for a contact for the group representing the user’s company. Or, assign
the can_view
permission to all users in a company when a contact is created by using signal or celery task.
Furthermore, you could use /contact/1/edit/
instead of /contact/edit/?id=1
. In this way the int(request.GET('id'))
part is moved to urlconf like r'^contact/(?P<pk>\d+)/$'
, less code and much clearer.
2đź‘Ť
If you use Django’s new class based views, e.g. the generic UpdateView, you can extend the dispatch
handler.
def dispatch(self, request, *args, **kwargs):
handler = super(MyEditView, self).dispatch(request, *args, **kwargs)
# Only allow editing if current user is owner
if self.object.author != request.user:
return HttpResponseForbidden(u"Can't touch this.")
return handler
In this case, the code verifies that the author
field of the model object corresponds to the currently logged in user, before even handling the rest of the request.
You can see a reallife example of this in a project of mine.
- [Answered ]-How to test a Django class-based view receives correct arguments?
- [Answered ]-Access request in django custom template tags, using the tag decorator
- [Answered ]-Django RegexValidator does not display message
- [Answered ]-Count objects assigned to the category in a django cycle
0đź‘Ť
There are some third-party apps that does what you want, its called “row-level permission” where you can give different users different access to specific objects, “Row level” comes from SQL where each object is a row in the database
I use django-guardian to do the job
0đź‘Ť
In the function handling the saving of the data, check to see if the object being edited has the same ID as the presently logged in user.
For example, if the object in question is called EmailPrefs and it has a field called user_id:
- Load the EmailPrefs object with the ID of the object being edited
- If the user_id does not match the current user, stop further processing
- Modify the EmailPrefs object
- Save the EmailPrefs object to the database
- [Answered ]-Django templates url parse error
- [Answered ]-Django South syncdb gives a SyntaxError
- [Answered ]-Display superscript in Django Admin