權限的功能及源碼流程

基本使用

問題:不一樣的視圖賦予不一樣的權限,以用來訪問python

views.pydjango

from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from api import models

ORDER_DICT = {
    1: {
        'name': 'qiu',
        'age': 18,
        'gender': '男',
        'content': '...'
    },

    2: {
        'name': 'xi',
        'age': 19,
        'gender': '男',
        'content': '.....'
    }
}


def md5(user):
    import hashlib
    import time

    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):

    authentication_classes = []

    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.UerInfo.objects.filter(username=user, password=pwd).first()
            if not obj:
                ret['code'] = 1001
                ret['msg'] = '用戶名或密碼錯誤'
            # 爲登陸用戶建立token
            else:
                token = md5(user)
                # 存在就更新, 不存在就建立
                models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1002
            ret['msg'] = '請求異常'

        return JsonResponse(ret)


class OrderView(APIView):
    '''
    訂單相關業務(只有SVIP用戶有權限)
    '''
    def get(self, request, *args, **kwargs):
        # 爲其添加權限,當爲SVIP用戶才能夠訪問
        if request.user.user_type != 3:
            return HttpResponse('無權訪問')

        ret = {'code': 1000, 'msg': None, 'data': None}
        try:
            ret['data'] = ORDER_DICT
        except Exception as e:
            pass
        return JsonResponse(ret)


class UserInfoView(APIView):
    '''
    用戶中心(普通用戶、VIP有權限)
    '''
    def get(self, request, *args, **kwargs):
        print(request.user)
        return HttpResponse('用戶信息')

user_type 爲 1 時,發送 GET 請求,獲得無權訪問api

若將 user_type 換爲 3,則可以訪問數據app

上面每一個不一樣的視圖函數都須要添加一個權限功能,能夠將它定義成一個類,在使用的時候直接調用,而且與視圖函數區分開,能夠在 utils 下新建 permission.py函數

views.pypost

from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from rest_framework.views import APIView
from api import models
from api.utils.permission import MyPermission, MyPermission1

ORDER_DICT = {
    1: {
        'name': 'qiu',
        'age': 18,
        'gender': '男',
        'content': '...'
    },

    2: {
        'name': 'xi',
        'age': 19,
        'gender': '男',
        'content': '.....'
    }
}


def md5(user):
    import hashlib
    import time

    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):

    authentication_classes = []

    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.UerInfo.objects.filter(username=user, password=pwd).first()
            if not obj:
                ret['code'] = 1001
                ret['msg'] = '用戶名或密碼錯誤'
            # 爲登陸用戶建立token
            else:
                token = md5(user)
                # 存在就更新, 不存在就建立
                models.UserToken.objects.update_or_create(user=obj, defaults={'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1002
            ret['msg'] = '請求異常'

        return JsonResponse(ret)


class OrderView(APIView):
    '''
    訂單相關業務(只有SVIP用戶有權限)
    '''
    permission_classes = [SVIPPermission]
    def get(self, request, *args, **kwargs):


        ret = {'code': 1000, 'msg': None, 'data': None}
        try:
            ret['data'] = ORDER_DICT
        except Exception as e:
            pass
        return JsonResponse(ret)


class UserInfoView(APIView):
    '''
    用戶中心(普通用戶、VIP有權限)
    '''
    permission_classes = [MyPermission]
    def get(self, request, *args, **kwargs):
        return HttpResponse('用戶信息')

permission.pyui

# -*- coding: utf-8 -*-

class SVIPPermission(object):
    message = "必須是SVIP用戶才能訪問"
    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

源碼流程

權限的源碼流程幾乎和認證是同樣的。首先從 dispatch,而後封裝 request,來到 initialthis

def initial(self, request, *args, **kwargs):
    ... # 省略的內容

    # Ensure that the incoming request is permitted
    self.perform_authentication(request)
    # 權限判斷
    self.check_permissions(request)
    self.check_throttles(request)

進入 check_permissionsspa

def check_permissions(self, request):
    """
    Check if the request should be permitted.
    Raises an appropriate exception if the request is not permitted.
    """
    
    '''
    self.get_permissions,首先去 OrderView 中找,沒有去父類中找
    在父類中返回了權限對象的列表
    '''
    for permission in self.get_permissions():
        if not permission.has_permission(request, self):
            self.permission_denied(
                request, message=getattr(permission, 'message', None)
            )
def get_permissions(self):
    """
    Instantiates and returns the list of permissions that this view requires.
    """
    # 對類進行實例化獲得權限對象的列表
    return [permission() for permission in self.permission_classes]

若是沒有對 self.permission_classes 設置,默認去配置文件中查找,若是設置了就使用設置的,以前在 views.py 中設置了 permission_classesrest

class APIView(View):
    ...
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    ...

也能夠將其設置爲全劇配置

settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthentication', 'api.utils.auth.Authentication'],
    'UNAUTHENTICATED_USER': None,
    'UNAUTHENTICATED_TOKEN': None,
    'DEFAULT_PERMISSION_CLASSES': ['api.utils.permission.SVIPPermission']

}

回到上一步的 check_permissions

def check_permissions(self, request):
    """
    Check if the request should be permitted.
    Raises an appropriate exception if the request is not permitted.
    """
    
    '''
    self.get_permissions,首先去 OrderView 中找,沒有去父類中找
    在父類中返回了權限對象的列表
    '''
    for permission in self.get_permissions():
        # 若是 permission.has_permission(request, self) 爲 False,才走裏面的代碼
        if not permission.has_permission(request, self):
            self.permission_denied(
                # 這裏有個message,是返回給用戶看的信息,能夠寫在本身的權限中
                request, message=getattr(permission, 'message', None)
            )
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)

權限的內置類

認證有內置的認證,權限也有內置的權限,所以在自定義權限的時候,爲了更加規範,須要繼承

permission.py

from rest_framework.permissions import BasePermission

class SVIPPermission(BasePermission):
    message = "必須是SVIP用戶才能訪問"
    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

總結

一、使用

  • 類,繼承 BasePermission,必須實現 has_permission 方法

  • 返回值

    • True:有權訪問
    • False:無權訪問
  • 全局

    'DEFAULT_PERMISSION_CLASSES': ['api.utils.permission.SVIPPermission']
  • 局部

    permission_classes = [MyPermission]

二、源碼流程

請求進來走 dispatch,先對 request 封裝,而後走 initial,先作認證,認證完成作權限,權限裏面把類拿過來作列表生成式生成對象,循環每個對象,執行 has_permission 方法

相關文章
相關標籤/搜索