1. 程式人生 > >Django rest framework 許可權操作(原始碼分析二)

Django rest framework 許可權操作(原始碼分析二)

知識回顧 

這一篇是基於上一篇寫的,上一篇謝了認證的具體流程,看懂了上一篇這一篇才能看懂,

當用戶訪問是 首先執行dispatch函式,當執行當第二部時:

   #2.處理版本資訊 處理認證資訊 處理許可權資訊 對使用者的訪問頻率進行限制
            self.initial(request, *args, **kwargs)

進入到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.
#2.1處理版本資訊 version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted #2.2處理認證資訊 self.perform_authentication(request)
#2.3處理許可權資訊 self.check_permissions(request) #2.4對使用者的訪問頻率進行限制 self.check_throttles(request)
複製程式碼
 #2.3處理許可權資訊
        self.check_permissions(request)

下面 開始 許可權的具體分析:

進入到check_permissions函式中

複製程式碼
 #檢查許可權
    def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        #elf.get_permissions()得到的是一個許可權物件列表
        for permission in self.get_permissions():
            #在自定義的Permission中has_permission方法是必須要有的
            #判斷當前has_permission返回的是True,False,還是丟擲異常
            #如果是True則表示許可權通過,False執行下面程式碼
            if not permission.has_permission(request, self):
                #為False的話則丟擲異常,當然這個異常返回的提示資訊是英文的,如果我們想讓他顯示我們自定義的提示資訊
                #我們重寫permission_denied方法即可
                self.permission_denied(
                    #從自定義的Permission類中獲取message(許可權錯誤提示資訊),一般自定義的話都建議寫上,如果沒有則為預設的(英文提示)
                    request, message=getattr(permission, 'message', None)
                )
複製程式碼

檢視permission_denied方法(如果has_permission返回True則不執行該方法)

複製程式碼
 def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """
        if request.authenticators and not request.successful_authenticator:
            #沒有登入提示的錯誤資訊
            raise exceptions.NotAuthenticated()
        #一般是登陸了但是沒有許可權提示
        raise exceptions.PermissionDenied(detail=message)
複製程式碼

 

舉例:

from django.db import models

# Create your models here.
class Userinfo(models.Model):
    name=models.CharField(max_length=32,verbose_name='使用者名稱')
    pwd=models.CharField(max_length=32,verbose_name='密碼')
    token=models.CharField(max_length=64,null=True)

    def __str__(self):
        return self.name
models
urlpatterns = [
    url(r'^p/', app02_views.Pview.as_view()),
    url(r'^mp/', app02_views.Aview.as_view()),
    url(r'^jp/', app02_views.Jview.as_view()),
]
urls
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework import exceptions


from app01 import models
# Create your views here.

class MyAuthentication(BaseAuthentication):

    def authenticate(self, request):
        token=request.query_params.get('token')
        user=models.Userinfo.objects.filter(token=token).first()
        if user:
            return (user.name,user)
        return None

class MyPermission(object):
    message = '登入才可以訪問'
    def has_permission(self,request, view):
        if request.user:
            return True
        return False

class AdminPermission(object):
    message = '會員才可以訪問'
    def has_permission(self,request,view):
        if request.user=='ctz':
            return True
        return False

class Pview(APIView):
    '''
    所有人都可以看
    '''
    authentication_classes = [MyAuthentication,]
    permission_classes = []
    def get(self,request):
        return Response('圖片列表')
    def post(self,request):
        pass




class Aview(APIView):
    '''
    登入的人可以看
    '''
    authentication_classes = [MyAuthentication,]
    permission_classes = [MyPermission,]
    def get(self,request):
        return Response('美國電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)

class Jview(APIView):
    '''
    會員才可以看
    '''
    authentication_classes = [MyAuthentication,]
    permission_classes = [MyPermission,AdminPermission,]
    def get(self,request):
        return Response('日本電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)
Views

上面的是區域性的只能在當前類中可以用,如果想在全域性中用:只需要在settings中配置即可:

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework import exceptions

from app02.utils import MyPermission
#
#
from app01 import models
# # Create your views here.
#
# class MyAuthentication(BaseAuthentication):
#
#     def authenticate(self, request):
#         token=request.query_params.get('token')
#         user=models.Userinfo.objects.filter(token=token).first()
#         if user:
#             return (user.name,user)
#         return None
#
# class MyPermission(object):
#     message = '登入才可以訪問'
#     def has_permission(self,request, view):
#         if request.user:
#             return True
#         return False
#
# class AdminPermission(object):
#     message = '會員才可以訪問'
#     def has_permission(self,request,view):
#         if request.user=='ctz':
#             return True
#         return False

class Pview(APIView):
    '''
    所有人都可以看
    '''

    permission_classes = []
    def get(self,request):
        return Response('圖片列表')
    def post(self,request):
        pass




class Aview(APIView):
    '''
    登入的人可以看
    '''
  #  authentication_classes = [MyAuthentication,]
    permission_classes = [MyPermission,]
    def get(self,request):
        return Response('美國電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)

class Jview(APIView):
    '''
    會員才可以看
    '''
    # authentication_classes = [MyAuthentication,]
    # permission_classes = [MyPermission,AdminPermission,]
    def get(self,request):
        return Response('日本電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)
Views
from django.shortcuts import render

from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.exceptions import APIException


from app01 import models
# Create your views here.

class MyAuthentication(BaseAuthentication):

    def authenticate(self, request):
        token=request.query_params.get('token')
        user=models.Userinfo.objects.filter(token=token).first()
        if user:
            return (user.name,user)
        return None

class MyPermission(object):
    message = '登入才可以訪問'
    def has_permission(self,request, view):
        if request.user:
            return True
        return False

class AdminPermission(object):
    message = '會員才可以訪問'
    def has_permission(self,request,view):
        if request.user=='ctz':
            return True
        return False
utils
REST_FRAMEWORK = {
    'UNAUTHENTICATED_USER': None,
    'UNAUTHENTICATED_TOKEN': None,
    "DEFAULT_AUTHENTICATION_CLASSES": [
      # "app01.utils.MyAuthentication",
        "app02.utils.MyAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES":[
       "app02.utils.MyPermission",
       "app02.utils.AdminPermission",
    ],
}
settings

 

知識回顧 

這一篇是基於上一篇寫的,上一篇謝了認證的具體流程,看懂了上一篇這一篇才能看懂,

當用戶訪問是 首先執行dispatch函式,當執行當第二部時:

   #2.處理版本資訊 處理認證資訊 處理許可權資訊 對使用者的訪問頻率進行限制
            self.initial(request, *args, **kwargs)

進入到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.
        #2.1處理版本資訊
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        #2.2處理認證資訊
        self.perform_authentication(request)
        #2.3處理許可權資訊
        self.check_permissions(request)
        #2.4對使用者的訪問頻率進行限制
        self.check_throttles(request)
複製程式碼
 #2.3處理許可權資訊
        self.check_permissions(request)

下面 開始 許可權的具體分析:

進入到check_permissions函式中

複製程式碼
 #檢查許可權
    def check_permissions(self, request):
        """
        Check if the request should be permitted.
        Raises an appropriate exception if the request is not permitted.
        """
        #elf.get_permissions()得到的是一個許可權物件列表
        for permission in self.get_permissions():
            #在自定義的Permission中has_permission方法是必須要有的
            #判斷當前has_permission返回的是True,False,還是丟擲異常
            #如果是True則表示許可權通過,False執行下面程式碼
            if not permission.has_permission(request, self):
                #為False的話則丟擲異常,當然這個異常返回的提示資訊是英文的,如果我們想讓他顯示我們自定義的提示資訊
                #我們重寫permission_denied方法即可
                self.permission_denied(
                    #從自定義的Permission類中獲取message(許可權錯誤提示資訊),一般自定義的話都建議寫上,如果沒有則為預設的(英文提示)
                    request, message=getattr(permission, 'message', None)
                )
複製程式碼

檢視permission_denied方法(如果has_permission返回True則不執行該方法)

複製程式碼
 def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """
        if request.authenticators and not request.successful_authenticator:
            #沒有登入提示的錯誤資訊
            raise exceptions.NotAuthenticated()
        #一般是登陸了但是沒有許可權提示
        raise exceptions.PermissionDenied(detail=message)
複製程式碼

 

舉例:

from django.db import models

# Create your models here.
class Userinfo(models.Model):
    name=models.CharField(max_length=32,verbose_name='使用者名稱')
    pwd=models.CharField(max_length=32,verbose_name='密碼')
    token=models.CharField(max_length=64,null=True)

    def __str__(self):
        return self.name
models
urlpatterns = [
    url(r'^p/', app02_views.Pview.as_view()),
    url(r'^mp/', app02_views.Aview.as_view()),
    url(r'^jp/', app02_views.Jview.as_view()),
]
urls
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework import exceptions


from app01 import models
# Create your views here.

class MyAuthentication(BaseAuthentication):

    def authenticate(self, request):
        token=request.query_params.get('token')
        user=models.Userinfo.objects.filter(token=token).first()
        if user:
            return (user.name,user)
        return None

class MyPermission(object):
    message = '登入才可以訪問'
    def has_permission(self,request, view):
        if request.user:
            return True
        return False

class AdminPermission(object):
    message = '會員才可以訪問'
    def has_permission(self,request,view):
        if request.user=='ctz':
            return True
        return False

class Pview(APIView):
    '''
    所有人都可以看
    '''
    authentication_classes = [MyAuthentication,]
    permission_classes = []
    def get(self,request):
        return Response('圖片列表')
    def post(self,request):
        pass




class Aview(APIView):
    '''
    登入的人可以看
    '''
    authentication_classes = [MyAuthentication,]
    permission_classes = [MyPermission,]
    def get(self,request):
        return Response('美國電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)

class Jview(APIView):
    '''
    會員才可以看
    '''
    authentication_classes = [MyAuthentication,]
    permission_classes = [MyPermission,AdminPermission,]
    def get(self,request):
        return Response('日本電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)
Views

上面的是區域性的只能在當前類中可以用,如果想在全域性中用:只需要在settings中配置即可:

from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework import exceptions

from app02.utils import MyPermission
#
#
from app01 import models
# # Create your views here.
#
# class MyAuthentication(BaseAuthentication):
#
#     def authenticate(self, request):
#         token=request.query_params.get('token')
#         user=models.Userinfo.objects.filter(token=token).first()
#         if user:
#             return (user.name,user)
#         return None
#
# class MyPermission(object):
#     message = '登入才可以訪問'
#     def has_permission(self,request, view):
#         if request.user:
#             return True
#         return False
#
# class AdminPermission(object):
#     message = '會員才可以訪問'
#     def has_permission(self,request,view):
#         if request.user=='ctz':
#             return True
#         return False

class Pview(APIView):
    '''
    所有人都可以看
    '''

    permission_classes = []
    def get(self,request):
        return Response('圖片列表')
    def post(self,request):
        pass




class Aview(APIView):
    '''
    登入的人可以看
    '''
  #  authentication_classes = [MyAuthentication,]
    permission_classes = [MyPermission,]
    def get(self,request):
        return Response('美國電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)

class Jview(APIView):
    '''
    會員才可以看
    '''
    # authentication_classes = [MyAuthentication,]
    # permission_classes = [MyPermission,AdminPermission,]
    def get(self,request):
        return Response('日本電影列表')
    def post(self,request):
        pass

    def permission_denied(self, request, message=None):
        """
        If request is not permitted, determine what kind of exception to raise.
        """

        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated('無權訪問')
        raise exceptions.PermissionDenied(detail=message)
Views
from django.shortcuts import render

from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.exceptions import APIException


from app01 import models
# Create your views here.

class MyAuthentication(BaseAuthentication):

    def authenticate(self, request):
        token=request.query_params.get('token')
        user=models.Userinfo.objects.filter(token=token).first()
        if user:
            return (user.name,user)
        return None

class MyPermission(object):
    message = '登入才可以訪問'
    def has_permission(self,request, view):
        if request.user:
            return True
        return False

class AdminPermission(object):
    message = '會員才可以訪問'
    def has_permission(self,request,view):
        if request.user=='ctz':
            return True
        return False
utils
REST_FRAMEWORK = {
    'UNAUTHENTICATED_USER': None,
    'UNAUTHENTICATED_TOKEN': None,
    "DEFAULT_AUTHENTICATION_CLASSES": [
      # "app01.utils.MyAuthentication",
        "app02.utils.MyAuthentication",
    ],
    "DEFAULT_PERMISSION_CLASSES":[
       "app02.utils.MyPermission",
       "app02.utils.AdminPermission",
    ],
}
settings