Search code examples
pythondjangodjango-rest-frameworkdjango-authenticationdjango-permissions

Django Permission Required


I'm trying to check permissions for some API requests. I've already set auth users and auth_user_user_permissions and auth_permissions tables like view_company add_company bla bla, but the problem is not that. The problem is when I'm trying yo use decorator which

@permission_required('API.view_company', raise_exception=True)

it said to me

AttributeError: 'CompanyDetailView' object has no attribute 'user'

Most probably it's looking for the user because its gonna check user_permission is it available to view companies or not but my view which I declared in urls.py (path('companies//', CompanyDetailView.as_view()),) has not have user object that's why error message returned attribute error, how can I solve this, thanks a lot

I tried to set example user in view class, in the beginning, it worked because view was looking for user object, i can not use that way because every request has different user

import rest_framework
from rest_framework import status
from django.contrib.auth.models import User
from rest_framework.views import APIView
from rest_framework.response import Response
from django.contrib.auth.decorators import permission_required

class CompanyDetailView(APIView):
    @permission_required('api.view_company', raise_exception=True)
    def get(self, request, id):
        try:
            request_data = {}
            request_data['request_method'] = request.method
            request_data['id'] = id
            companies = Company.objects.get(id=id)
            status = rest_framework.status.HTTP_200_OK
            return Response(companies, status)

bla bla bla

url line was =

path('companies/<int:id>/', CompanyDetailView.as_view()),

my error message was : AttributeError: 'CompanyDetailView' object has no attribute 'user'

when i debug and i see request.user.has_perm('view_company')returned false but still api give responses, it suppose to say you are not allow to view companies


Solution

  • The mechanism of Django Views and Django Rest Framework Views are a bit different, that's why you've got that error message. permission_required will try to access user field of your view to check user permission using has_perm method. But APIView didn't have user field inside of it.

    To get rid of this, you might want to use permissions which provided by Django Rest Framework to restrict the access.

    But if you still want to use built-in permission of Django to restrict the access to your view, you could create a Permission class which will use has_perm to check user permission. Like so:

    from rest_framework import permissions
    from rest_framework import exceptions
    
    class ViewCompanyPermission(permissions.BasePermission):
        def has_permission(self, request, view):
            if not request.user.has_perm('api.view_company'):
                raise exceptions.PermissionDenied("Don't have permission")
            return True
    

    and use it on your view via permission_classes field:

    class CompanyDetailView(APIView):
        permission_classes = (ViewCompanyPermission, )
        def get(self, request, id):
            try:
                request_data = {}
                request_data['request_method'] = request.method
                request_data['id'] = id
                companies = Company.objects.get(id=id)
                status = rest_framework.status.HTTP_200_OK
                return Response(companies, status)
    

    In case you want to replicas the permission_required behavior, you could do something like this:

    from rest_framework import permissions
    from rest_framework import exceptions
    
    def permission_required(permission_name, raise_exception=False):
        class PermissionRequired(permissions.BasePermission):
            def has_permission(self, request, view):
                if not request.user.has_perm(permission_name):
                    if raise_exception:
                        raise exceptions.PermissionDenied("Don't have permission")
                    return False
                return True
        return PermissionRequired
    

    Then you can use it like:

    class CompanyDetailView(APIView):
        permission_classes = (permission_required("api.view_company", raise_exception=True), )
        # ...