zoukankan      html  css  js  c++  java
  • DRF的认证、权限 和 限制

    一、概述

    认证是将传入请求与一组标识凭据(例如请求来自的用户或其签名的令牌)相关联的机制。然后 权限 和 限制 组件决定是否拒绝这个请求。

    简单来说就是:

    认证确定了你是谁

    权限确定你能不能访问某个接口

    限制确定你访问某个接口的频率

    二、认证

    REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案。

    三、自定义Token认证

    model 定义一个包含token字段的用户表

    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        vip = models.BooleanField(default=False)
        token = models.CharField(max_length=128, null=True, blank=True)

    定义登录视图:

    class LoginView(APIView):
        def post(self, request):
            name = request.data.get('name')
            pwd = request.data.get('pwd')
            if name and pwd:
                user_obj = models.UserInfo.objects.filter(name=name, pwd=pwd).first()
                if user_obj:
                    # 登陆成功
                    # 生成token(时间戳 + Mac地址)
                    token = uuid.uuid1().hex
                    # 1.保存在用户表中
                    user_obj.token = token
                    user_obj.save()
                    # 2.给用户返回
                    return Response({'error_no': 0, 'token': token})
    
                else:
                    # 用户名或密码错误
                    return Response({'error_no': 1, 'error': '用户名或密码错误'})
            else:
                return Response('无效的参数')

    创建auth.py自定义一个认证类

    from rest_framework.authentication import BaseAuthentication
    from auth_demo import models
    from rest_framework.exceptions import AuthenticationFailed
    
    
    class MyAuth(BaseAuthentication):
        '''自定义认证类'''
    
        def authenticate(self, request):
            token = request.query_params.get ('token')
            if token:
                # 如果请求url中携带有token参数
                user_obj = models.UserInfo.objects.filter(token=token).first()
                if user_obj:
                    # token 是有效的,返回一个元组
                    return user_obj, token  # request.user, request.auth
                else:
                    raise AuthenticationFailed('无效的token')
            else:
                raise AuthenticationFailed('请求的URL中必须携带token参数')

    局部配置认证

    在views中自定义一个测试类TestAuthView

    from auth_demo.auth import MyAuth
    from auth_demo.permissions import MyPermission
    # 登录之后才能看到数据接口
    class TestAuthView(APIView):
        authentication_classes = [MyAuth, ]  # 局部配置认证
    
        def get(self, request):
            print(request.user.name)
            print(request.auth)
            return Response('这个视图里面的数据只有登录后才能看到!')

    全局配置认证

    # 在settings.py中配置
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": ["auth_demo.auth.MyAuth", ] 
    }

     四、权限

    自己动手写一个权限组件

    from rest_framework.permissions import BasePermission
    
    
    class Mypermission(BasePermission):
        message = '只有VIP才能访问'
    
        def has_permission(self, request, view):
            # vip才有访问权限
            # request.user:当前经过认证的用户对象
            # 如果没有认证 request.user就是匿名用户
            if not request.auth:
                # 认证没有通过
                return False
            if request.user.vip:
                return True
            else:
                return False

    视图级别配置

    from auth_demo.auth import MyAuth
    from auth_demo.permissions import Mypermission
    # 登录之后才能看到数据接口
    class TestAuthView(APIView):
        authentication_classes = [MyAuth, ]  # 局部配置认证
        permission_classes = [Mypermission, ] # 试图级别配置权限
    
        def get(self, request):
            print(request.user.name)
            print(request.auth)
            return Response('这个视图里面的数据只有登录后才能看到!')

    全局级别设置

    只需要在settings的DRF配置项中添加权限类

    # DRF的配置
    REST_FRAMEWORK = {
        # 配置默认使用的版本控制类
        'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
        # 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning',# url参数控制版本
        'DEFAULT_VERSION': 'v1',  # 默认的版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],  # 有效的版本
        'VERSION_PARAM': 'version',  # 版本的参数名与URL conf中一致
        # 自定义认证
        'DEFAULT_AUTHENTICATION_CLASSES': ['auth_demo.auth.MyAuth', ],
        # 自定义权限
        'DEFAULT_PERMISSION_CLASSES': ['auth_demo.permissions.MyPermission', ]
    }

    五、限制

    DRF内置了基本的限制类,首先自己动手写一个限制类,熟悉限制组件的执行过程。

    自定义限制10秒内只能访问3次

    自定义的限制类必须实现2个方法

    allow_request() 和 wait()
    分析:
    # history = ['9:56:12', '9:56:10', '9:56:09', '9:56:08']  # '9:56:18' - '9:56:12'
    
    # history = ['9:56:19', '9:56:18', '9:56:17', '9:56:08']
    
    # 最后一项到期的时间就是下一次允许请求的时间
    
    # 最后一项到期的时间:history[-1] + 10
    
    # 最后一项还剩多少时间过期
    # history[-1] + 10 - now

    实现:

    import time
    
    # 存放访问记录信息
    visit_record= {}
    class MyThrottle(object):
        def __init__(self):
            self.history = None
    
        def allow_request(self, request, view):
            # 拿到当前请求的ip作为访问记录的key
            ip = request.META.get('REMOTE_ADDR')
            # 拿到当前请求的时间戳
            now = time.time()
            if ip not in visit_record:
                visit_record[ip] = []
            # 把当前请求的访问记录拿出来保存到一个变量中
            history = visit_record[ip]
            self.history = history
            # 循环访问历史,把超过10秒中的请求时间去掉
            while history and now - history[-1] > 10:
                history.pop()
            # 此时 history中只保存了最近10秒中的访问记录
            if len(history) >= 3:
                # 限制十秒钟内最多只能访问三次
                return False
            else:
                # 将当前访问时间插入history的首位
                self.history.insert(0, now)
                return True
    
        def wait(self):
            '''告诉客户还需等待多久'''
            now = time.time()
            return self.history[-1] + 10 - now

    单个视图类使用

    from auth_demo.auth import MyAuth
    from auth_demo.permissions import MyPermission
    from auth_demo.throttle import MyThrottle
    # 登录之后才能看到数据接口
    class TestAuthView(APIView):
        authentication_classes = [MyAuth, ]  # 局部配置认证
        permission_classes = [MyPermission, ] # 视图级别配置权限
        throttle_classes = [MyThrottle, ] # 限制单个视图访问频率
    
        def get(self, request):
            print(request.user.name)
            print(request.auth)
            return Response('这个视图里面的数据只有登录后才能看到!')

    全局使用

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['auth_demo.auth.MyAuth', ],
        'DEFAULT_PERMISSION_CLASSES': ['auth_demo.permissions.MyPermission', ]
        
    "DEFAULT_THROTTLE_CLASSES": ["auth_demo.throttle.MyThrottle", ] }

    使用内置限制类

    from rest_framework.throttling import SimpleRateThrottle
    
    
    class VisitThrottle(SimpleRateThrottle):
    
        scope = "xxx"
    
        def get_cache_key(self, request, view):
            return self.get_ident(request)

    全局配置

    settings的REST_FRAMEWORK配置中加一个:
    REST_FRAMEWORK = {
        # 限制类
        "DEFAULT_THROTTLE_CLASSES": ["auth_demo.throttle.VisitThrottle", ],
        "DEFAULT_THROTTLE_RATES": {
            "xxx": "1/s",
        },
    }
  • 相关阅读:
    C语言I博客作业03
    C语言I博客作业02
    macwingIDE python3.5 配置
    JAVA必会算法插入排序
    java匿名内部类的另一个用途
    JAVA必会算法选择排序
    Mac elasticsearch 5.2.2 单机双节点配置
    JAVA必会算法二分查找法
    AOP 事物连接,记忆连接数据库,连接池
    线程的意义与一些常见面试问题
  • 原文地址:https://www.cnblogs.com/zwq-/p/10274204.html
Copyright © 2011-2022 走看看