Django rest framework source code analysis -- permission

Note: the following permission content is written on the basis of authentication. It's better to read the article after the authentication

1, Add permission

(1) Create a new permission.py file in the API / utils folder. The code is as follows:
Message is the message prompted when there is no permission

# utils/permission.py
class SVIPPermission(object):
    message = "Must be SVIP Ability to visit"
    def has_permission(self,request,view):
        if request.user.user_type != 3:
            return False
        return True
        
class MyPermission(object):
    def has_permission(self,request,view):
        if request.user.user_type == 3:
            return False
        return True

(2)settings.py global configuration permission

#Overall situation
REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES":['API.utils.auth.Authentication',],
    "DEFAULT_PERMISSION_CLASSES":['API.utils.permission.SVIPPermission'],
}

(3)views.py add permission
By default, all businesses need SVIP permission to access
There is no SVIPPermission in the OrderView class indicating the use of global configuration
The UserInfoView class is accessible to ordinary users and VIP users. If you want to use it locally, you need to write your own permission class

permission_classes = [MyPermission,]   #Local permission method
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from API import models
from rest_framework.request import Request
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication
from API.utils.permission import SVIPPermission,MyPermission

ORDER_DICT = {
    1:{
        'name':'apple',
        'price':15
    },
    2:{
        'name':'dog',
        'price':100
    }
}

def md5(user):
    import hashlib
    import time
    #Current time, equivalent to generating a random string
    ctime = str(time.time())
    m = hashlib.md5(bytes(user,encoding='utf-8'))
    m.update(bytes(ctime,encoding='utf-8'))
    return m.hexdigest()

class AuthView(APIView):
    '''For user login authentication'''

    authentication_classes = []      #It is empty, which means no authentication is required
    permission_classes = []          #No, it's empty, which means you don't need permission
    def post(self,request,*args,**kwargs):
        ret = {'code':1000,'msg':None}
        try:
            user = request._request.POST.get('username')
            pwd = request._request.POST.get('password')
            obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
            if not obj:
                ret['code'] = 1001
                ret['msg'] = 'Wrong user name or password'
            #Create token for user
            token = md5(user)
            #Update if it exists, create if it doesn't exist
            models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
            ret['token'] = token
        except Exception as e:
            ret['code'] = 1002
            ret['msg'] = 'Request exception'
        return JsonResponse(ret)


class OrderView(APIView):
    '''
    //Order related business (only SVIP users can view it)
    '''

    def get(self,request,*args,**kwargs):
        self.dispatch
        #request.user
        #request.auth
        ret = {'code':1000,'msg':None,'data':None}
        try:
            ret['data'] = ORDER_DICT
        except Exception as e:
            pass
        return JsonResponse(ret)


class UserInfoView(APIView):
    '''
       //Order related business (common users and VIP users can see it)
       '''
    permission_classes = [MyPermission,]    #Without global permission configuration, you need to write your own local permission here
    def get(self,request,*args,**kwargs):

        print(request.user)
        return HttpResponse('User information')
# urls.py
from django.contrib import admin
from django.urls import path
from API.views import AuthView,OrderView,UserInfoView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/auth/',AuthView.as_view()),
    path('api/v1/order/',OrderView.as_view()),
    path('api/v1/info/',UserInfoView.as_view()),
]


# API/utils/auth/py

from rest_framework import exceptions
from API import models
from rest_framework.authentication import BaseAuthentication


class Authentication(BaseAuthentication):
    '''For user login authentication'''
    def authenticate(self,request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('User authentication failed')
        #These two fields are assigned to request in the rest framework for subsequent operations
        return (token_obj.user,token_obj)

    def authenticate_header(self, request):
        pass

auth.py

(4) testing

Ordinary user accesses OrderView and prompts that they have no permission

Ordinary users can access UserInfoView and return information

2, Permission source flow

(1)dispatch

def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        #Processing the original request enriches some functions
        #Request(
        #     request,
        #     parsers=self.get_parsers(),
        #     authenticators=self.get_authenticators(),
        #     negotiator=self.get_content_negotiator(),
        #     parser_context=parser_context
        # )
        #Request (original request,[BasicAuthentications object,])
        #Get native request, request
        #Get the object of the authentication class, request.authenticators
        #1. Package request
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            #2. certification
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

(2)initial

def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        #4. Achieve authentication
        self.perform_authentication(request)
        #5. Authority judgment
        self.check_permissions(request)
        self.check_throttles(request)

(3)check_permissions
There's a has'permission in it, which is the permission judgment written by ourselves

def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        #[list of objects of permission class]
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(
                #Get the message property through the reflection mechanism. Message is the message prompted when there is no permission
                    request, message=getattr(permission, 'message', None)
                )

(4)get_permissions

def get_permissions(self):
        """
        Instantiates and returns the list of permissions that this view requires.
        """
        return [permission() for permission in self.permission_classes]

(5)permission_classes
Configure the file according to permission ﹣ classes = API ﹣ settings.default ﹣ permission ﹣ classes
So the settings global configuration is as follows

#Overall situation
REST_FRAMEWORK = {
   "DEFAULT_PERMISSION_CLASSES":['API.utils.permission.SVIPPermission'],
}

3, Built in permissions

Django rest framework built in permission BasePermission
The default is no permission restriction

class BasePermission(object):
    """
    A base class from which all permission classes should inherit.
    """

    def has_permission(self, request, view):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

The permission class written by ourselves should inherit BasePermission and modify the permission.py file written before

# utils/permission.py

from rest_framework.permissions import BasePermission

class SVIPPermission(BasePermission):
    message = "Must be SVIP Ability to visit"
    def has_permission(self,request,view):
        if request.user.user_type != 3:
            return False
        return True


class MyPermission(BasePermission):
    def has_permission(self,request,view):
        if request.user.user_type == 3:
            return False
        return True

5, Summary:

(1) use

Permission class written by oneself: 1. Must inherit BasePermission class; 2. Must implement: has'permission method

(2) return value

True has access
 False no access

(3) local

permission_classes = [MyPremission,] 

(4) overall situation

REST_FRAMEWORK = {
   #Jurisdiction
    "DEFAULT_PERMISSION_CLASSES":['API.utils.permission.SVIPPremission'],
}
Published 5 original articles, won praise 1, visited 4062
Private letter follow

Tags: Django encoding REST

Posted on Sun, 09 Feb 2020 22:14:57 -0800 by james19