Loading

权限的功能及源码流程

基本使用

问题:不同的视图赋予不同的权限,以用来访问

views.py

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 请求,得到无权访问

若将 user_type 换为 3,则能够访问数据

上面每个不同的视图函数都需要添加一个权限功能,可以将它定义成一个类,在使用的时候直接调用,并且与视图函数区分开,可以在 utils 下新建 permission.py

views.py

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.py

# -*- 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,来到 initial

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_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():
        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_classes

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

总结

1、使用

  • 类,继承 BasePermission,必须实现 has_permission 方法

  • 返回值

    • True:有权访问
    • False:无权访问
  • 全局

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

    permission_classes = [MyPermission]
    

2、源码流程

请求进来走 dispatch,先对 request 封装,然后走 initial,先做认证,认证完成做权限,权限里面把类拿过来做列表生成式生成对象,循环每一个对象,执行 has_permission 方法

posted @ 2019-02-26 10:11  湫兮  阅读(390)  评论(0编辑  收藏  举报