权限的功能及源码流程

基本使用

问题:不一样的视图赋予不一样的权限,以用来访问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 方法

相关文章
相关标签/搜索