• 06 drf认证,权限与频率


    一.认证

    1.1 认证的简单实现

    写一个类,继承BaseAuthentication,authenticate,认证的逻辑写在里面,认证通过,返回两个值,一个值最终给了Request对象的user,认证失败,抛异常:APIException或者AuthenticationFailed
    

    1.2 自定义认证方案

    1.2.1在models中创建

    class User(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
        user_type = models.IntegerField(choices=((1, '超级用户'), (2, '普通用户'), (3, '二笔用户')))
    
    
    class UserToken(models.Model):
        token = models.CharField(max_length=64)
        user = models.OneToOneField(to=User, on_delete=models.CASCADE)  # 一对一关联到User表
    

    1.2.2 新建一个认证类

    class MyAuthentication(BaseAuthentication):
        def authenticate(self, request):
            # 认证逻辑,如果认证通过,返回两个值
            # 如果认证失败,抛出AuthenticationFailed异常
            token = request.GET.get('token')
            if token:
                user_token = UserToken.objects.filter(token=token).first()
                # 认证通过
                if user_token:
                    return user_token.user, token
                else:
                    raise AuthenticationFailed('认证失败')
            else:
                raise AuthenticationFailed('请求地址中需要携带token')
    

    1.2.3 编写视图

    class LoginView(APIView):
        authentication_classes = []   # 局部禁用
    
        def post(self, request):
            username = request.data.get('username')
            password = request.data.get('password')
            user = models.User.objects.filter(username=username, password=password).first()
            if user:
                # 登陆成功,生成一个随机字符串
                token = uuid.uuid4()
                # 存到UserToken表中
                # models.UserToken.objects.create(token=token,user=user)# 用它每次登陆都会记录一条,不好,如有有记录
                # update_or_create有就更新,没有就新增
                models.UserToken.objects.update_or_create(defaults={'token': token}, user=user)
                return Response({'status': 100, 'msg': '登陆成功', 'token': token})
            else:
                return Response({'status': 101, 'msg': '用户名或密码错误'})
    

    1.3 认证的全局使用和局部使用

    1.3.1 认证全局使用

    # 全局使用,在setting.py中配置
    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
    }
    

    1.3.2 认证局部使用

    # 局部使用,在视图类上写
    authentication_classes=[MyAuthentication]
    

    1.3.3 认证局部禁用

    # 局部禁用,在视图类上写
    authentication_classes=[]
    

    1.4 认证的源码分析

    #1 APIVIew----》dispatch方法---》self.initial(request, *args, **kwargs)---->有认证,权限,频率
    
    #2 只读认证源码: self.perform_authentication(request)
    
    #3 self.perform_authentication(request)就一句话:request.user,需要去drf的Request对象中找user属性(方法) 
    
    #4 Request类中的user方法,刚开始来,没有_user,走 self._authenticate()
    
    #5 核心,就是Request类的 _authenticate(self):
    	def _authenticate(self):
        # 遍历拿到一个个认证器,进行认证
        # self.authenticators配置的一堆认证类产生的认证类对象组成的list
        #self.authenticators 你在视图类中配置的一个个的认证类:		      authentication_classes=[认证类1,认证类2],对象的列表
            for authenticator in self.authenticators:
                try:
          # 认证器(对象)调用认证方法authenticate(认证类对象self, request请求对象)
          # 返回值:登陆的用户与认证的信息组成的 tuple
          # 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败
        user_auth_tuple = authenticator.authenticate(self) 
          #注意这self是request对象
                except exceptions.APIException:
                    self._not_authenticated()
                    raise
    
         # 返回值的处理
    if user_auth_tuple is not None:
        self._authenticator = authenticator
        # 如何有返回值,就将 登陆用户 与 登陆认证 分别保存到 request.user、request.auth
        self.user, self.auth = user_auth_tuple
                    return
        # 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登陆用户 与 登陆认证信息,代表游客
            self._not_authenticated()
    

    二.权限Permissions

    权限控制可以限制用户对于视图的访问和对于具体数据对象的访问。

    • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
    • 在通过get_object()获取具体对象时,会进行模型对象访问权限的判断

    2.1 权限的源码简单分析

    # APIView---->dispatch---->initial--->self.check_permissions(request)(APIView的对象方法)
    def check_permissions(self, request):
        # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证
        for permission in self.get_permissions():
        # 权限类一定有一个has_permission权限方法,用来做权限认证的
        # 参数:权限对象self、请求对象request、视图类对象
        # 返回值:有权限返回True,无权限返回False
            if not permission.has_permission(request, self):
                self.permission_denied(
                   request,message=getattr(permission,'message', None)
                    )
    
    

    2.2 权限使用

    写一个类,继承BasePermission,重写has_permission,如果权限通过,就返回True,不通过就返回False

    from rest_framework.permissions import BasePermission
    
    class UserPermission(BasePermission):
        def  has_permission(self, request, view):
            # 不是超级用户,不能访问
            # 由于认证已经过了,request内就有user对象了,当前登录用户
            user=request.user  # 当前登录用户
            # 如果该字段用了choice,通过get_字段名_display()就能取出choice后面的中文
            print(user.get_user_type_display())
            if user.user_type==1:
                return True
            else:
                return False
    
    

    2.3 权限的全局使用和局部禁用

    # 局部使用
    class TestView(APIView):
        permission_classes = [app_auth.UserPermission]
    
    
    # 全局使用
    REST_FRAMEWORK={
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",],
        'DEFAULT_PERMISSION_CLASSES': [
            'app01.app_auth.UserPermission',
        ],
    }
    
    
    # 局部禁用
    class TestView(APIView):
        permission_classes = []
    
    

    三. 频率

    3.1 内置的频率限制(限制未登录的用户)

    # 全局使用  限制未登录用户1分钟访问3次
    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.AnonRateThrottle',
        ),
        'DEFAULT_THROTTLE_RATES': {
            'anon': '3/m',
        }
    }
    
    
    # views.py
    from rest_framework.permissions import IsAdminUser
    from rest_framework.authentication import SessionAuthentication,BasicAuthentication
    class TestView4(APIView):
        authentication_classes=[]
        permission_classes = []
        def get(self,request,*args,**kwargs):
            return Response('未登录用户')
    
    
    # 局部使用
    from rest_framework.permissions import IsAdminUser
    from rest_framework.authentication import SessionAuthentication,BasicAuthentication
    from rest_framework.throttling import AnonRateThrottle
    class TestView5(APIView):
        authentication_classes=[]
        permission_classes = []
        throttle_classes = [AnonRateThrottle]
        def get(self,request,*args,**kwargs):
            return Response('我是未登录用户,TestView5')
    
    

    3.2 内置频率限制,限制登录用户的访问频率

    # 需求:未登录用户1分钟访问5次,登录用户一分钟访问10次
    全局:在setting中
      'DEFAULT_THROTTLE_CLASSES': (
            'rest_framework.throttling.AnonRateThrottle',
            'rest_framework.throttling.UserRateThrottle'
        ),
        'DEFAULT_THROTTLE_RATES': {
            'user': '10/m',
            'anon': '5/m',
        }
            
     局部配置:
    	在视图类中配置
    
    
  • 相关阅读:
    js返回上一页并刷新思路
    C#字符串拼接
    html2canvas截图问题,图片跨域导致截图空白
    VS2017未能添加对"System.Drawing.dll"的引用
    微信小程序云开发获取文件夹下所有文件
    js解析json报错Unexpected token i in JSON at position 1
    人工智能学习
    suricata的模块和插槽
    学习助手开发(二)——表单排序
    成功在Caterpillar代码中插入事件对象-20200917
  • 原文地址:https://www.cnblogs.com/bailongcaptain/p/13279471.html
Copyright © 2020-2023  润新知