In Django I'm trying to implement some kind of a "security middleware", which gives access to certain db information only, if the logged in user matches.

Up to now I found two approaches: middleware or custom function in manager (Both explained here Django custom managers - how do I return only objects created by the logged-in user?).

Example for cleanest solution: custom function

class UserContactManager(models.Manager):
    def for_user(self, user):
        return self.get_query_set().filter(creator=user)

class MyUser(models.Model):
    # Managers
    objects = UserContactManager()

# then use it like this in views
data = MyUser.objects.for_user(request.user)

However, this solution only works, if you have control over the code which invokes this custom function (here: for_user()). But if you are using third parties apps like Django-REST, Graphene or AdminViews, they don't have the possibility to configure a specific query-func to use.

My goal:

  1. Replace the default Manager
  2. Add user-based filters to query_set
  3. Use the model as normal in all app configurations

Idea (pseudo code!)

from django.x import current_user

class UserBasedManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(author=current_user.name)

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.CharField(max_length=50)

    objects = UserBasedManager() # The default manager.

Now I could use the model Book as normal in all extensions.

I know this solution would have some drawbacks, which are okay for me:

  • Can be only used when user is available (e.g. no direct script support)
  • Handling no or anonymous user is missing (left it away to keep example short)

My use case

I have a project, which shall give access to data by different interfaces (admin pages, custom views, rest, graphql). As I have so many interfaces, I don't want to implement the access-rights in the views. This would cost too much time and is hard to maintain and the risk for security problems in one specific view/interface is too high.

Let's say I'm storing commits of git repositories in a database. And the user shall get access to all commits, which are part of repos the user has READ access.

The question is: How can I implement this as a generic, view/interface independent solution?

1

There are 1 answers

1
Ivan Cvetković On

Install django-threadlocals package and call get_current_user function to get the current user

from threadlocals.threadlocals import get_current_user

class UserBasedManager(models.Manager):
    def get_queryset(self):
        current_user = get_current_user()
        return super().get_queryset().filter(author=current_user.name)