[Answered ]-How to restrict editing of records to the logged-in user?

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.

👤okm

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.

👤Danilo Bargen

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

👤krs

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:

  1. Load the EmailPrefs object with the ID of the object being edited
  2. If the user_id does not match the current user, stop further processing
  3. Modify the EmailPrefs object
  4. Save the EmailPrefs object to the database

Leave a comment