zoukankan      html  css  js  c++  java
  • 权限的功能及源码流程

    基本使用

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

    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 方法

  • 相关阅读:
    Spring国际化模块
    广告牌 循环 轮播 图片
    ImageLoader 网络加载图片
    ProgressBar 进度条 旋转
    UI处理 线程
    权限 动态 访问
    系统 状态栏 导航栏
    对话框 dialog 整理
    修改 字体
    获取 Activity中所有的View ViewGroup
  • 原文地址:https://www.cnblogs.com/qiuxirufeng/p/10435549.html
Copyright © 2011-2022 走看看