Django Ninja permissions

Hello, i hope i can get some help with this challenge.

I am working on an app that will use vue js for the custom admin and the frontend.
So there will be a dashboard where users can manage all crud operations for all models and everything, currently it is a practice project, where i want to redo my elearning web app that is using normal Django.

So let’s say there is a model named Course, and it has two fields, to make it simple. A course title and a relation to the creator/owner.

class Course(models.Model):
    title = models.CharField(max_length=255)
    owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='owners_courses')

    def __str__(self):
        return self.title

Courses app has schema.py

from ninja import ModelSchema
from .models import Course

class CourseSchema(ModelSchema):
    class Meta:
        model = Course
        fields = ['id','title','owner']

and api.py, then on the router “/courses” we have all our Django ninja paths.


class TokenAuth(HttpBearer):
    def authenticate(self, request, token):
        return get_object_or_404(User, token=token)

@router.get('/list', response=list[CourseSchema], auth=TokenAuth())
def list_courses(request):
    courses = Course.objects.all()
    return courses

My custom user model has the token field which gets created automatically, and then i have this TokenAuth for authentication. That is all okay, i think.

Login api


# USER LOGIN
@router.post('/login')
def login_view(request, data:UserLoginSchema):
    User = get_user_model()
    user = authenticate(
        email = data.email,
        password = data.password
    )

    if user is None:
        return {
            "success":False, 
            "detail":"Invalid credentials"
            }
    
    if user.deleted:
        return {
            "success":False, 
            "detail":"Your account is deleted, contact support"
            }
    
    #token = user.token
    # generate new token
    user.token = uuid.uuid4().hex
    user.save()
    
    return {
        "success": True,
        "token": user.token
    }

But how do we create and work with Permissions?

I hope somebody can help please :slight_smile:
Best regards from Serbia.
Thank you all!

Default permissions are created with every model. Custom permssions can be created by adding them in your model Meta class, or programmatically, perhaps in a data migration or custom admin command.

Working with them is described in detail at Using the Django authentication system | Django documentation | Django.

But briefly, each view can be given the opportunity to check the permissions assigned to a user (and by extension, the permissions assigned to all the groups that the user is a member of), to determine whether the user making the request has the authority to use that view. (Note that by writing your own authorization tests, you can make these tests much more sophisticated than simply “does this user have this permission.”)

Hi, thank you. Here is one example.

class TokenAuth(HttpBearer):
    def authenticate(self, request, token):
        user = get_object_or_404(User, token=token)
        request.user = user
        return user

@router.get('/list', response=list[CourseSchema], auth=TokenAuth())
def list_courses(request):    
    courses = Course.objects.all()
    return courses


@router.post('/create', response=CourseSchema, auth=TokenAuth())
def create_course(request, data: CourseCreateSchema):
    user = request.user

    if not request.user.is_staff:
        raise HttpError(403, "You are no staff.")
    
    if Course.objects.filter(title=data.title).exists():
        raise HttpError(400, 'This title already exists.')

    course_data = data.dict() 
    course_data['owner'] = user
    new_course = Course.objects.create(**course_data)
    return new_course

First in the custom user we have the token field. So now in TokenAuth i have to call for the user because i can not use request.user in django-ninja, so later in each api, i can check what i want.

Is that a correct approach?

Thank you

1 Like

What is this “HttpBearer”? It’s not a Django class.

And I’m sorry, but I don’t know anything about Django-ninja. (I would find it hard to believe that it doesn’t make request.user available to you, that seems extremely counter-productive. If there’s no way to get the requesting user from the request, then I don’t see how any permission structure can work.)

HttpBearer is import like this
from ninja.security import HttpBearer

Now, when i create TokenAuth like this:

class TokenAuth(HttpBearer):
    def authenticate(self, request, token):
        return get_object_or_404(User, token=token)

For some reason it doesn’t recognize the user from the request and in Postman i get this message in submit
“You no staff”

But when i create TokenAuth like this:

class TokenAuth(HttpBearer):
    def authenticate(self, request, token):
        user = get_object_or_404(User, token=token)
        request.user = user
        return user

Then it does recognize it.

The api for course create did not change.

@router.post(‘/create’, response=CourseSchema, auth=TokenAuth())
def create_course(request, data: CourseCreateSchema):
user = request.user

if not request.user.is_staff:
    raise HttpError(403, "You no staff")

if Course.objects.filter(title=data.title).exists():
    raise HttpError(400, 'This name occupied')

course_data = data.dict() 
course_data['owner'] = user
new_course = Course.objects.create(**course_data)
return new_course

But it is all working, i mean, these checks all work, if i am not a staff user i see the message, if i am, my post goes through and the object is created.

I have to define request.user in TokenAuth in order to be able to use it in api views, i think that is the solution.

Mark the post that helped you as a solution.