zoukankan      html  css  js  c++  java
  • Django REST framework 之 认证 权限 限制

    认证是确定你是谁

    权限是指你有没有访问这个接口的权限

    限制主要是指限制你的访问频率

    认证

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

    接下类我们就自己动手实现一个基于Token的认证方案:

    自定义Token认证

    定义一个用户表和一个保存用户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('无效的参数')

    定义一个认证类

    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参数')

    视图级别的认证:

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

    全局级别认证

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

    权限

    只有VIP用户才能看的内容。

    自定义一个权限类

    from rest_framework.permissions import BasePermission
    
    
    class MyPermission(BasePermission):
        message = '只有VIP才能访问'
    
        def has_permission(self, request, view):
             if not request.auth:  # 用户登录确认
                  return False 
            
            # 如果你是VIP才有权限访问
            # request.user:当前经过认证的用户对象
            if request.user.vip:
                return True
            else:
                # 如果不是VIP就拒绝范围跟
                return False

    视图级别认证:

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

    全局级别设置

    # 在settings.py中设置rest framework相关配置项
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
        "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
    }

    限制

    自定义一个限制访问的类

    import time
    """
    自定义一个限制
    """
    # 创建一个空的字典
    visit = {} 
    
    
    class BaseThrottle(object):
        def __init__(self):
            self.history = None
    
        def allow_request(self, request, view):
            ip = request.META.get('REMOTE_ADDR')  # 获取用户的ip地址
            now = time.time()  # 获取当前时间
    
            if ip not in visit:  # 第一次进来的时候 字典中没有以ip为key的键值对
                visit[ip] = []  # 创建一个以ip为key的键值对
            history = visit[ip]  # 如果不是第一次访问的话 获取一下以ip为key的对应的值
            self.history = history  # 因为wait方法中也会用到history的值,所以把history升级成类属性
            while history and now - history[-1] > 10:  # 循环判断一下 如果当前时间与history里面的最先插入的时间大于10秒
                history.pop()  # 就删除最后的先插入的那个数据
            if len(history) >= 3:  # 如果10秒内history里面的时间戳大于3个,表示查询过于频繁,限制一下,返回false
                return False
            else:  # 如果10秒钟内没有三个时间戳,再来访问的话是可以的,记录一下当前访问的时间戳
                history.insert(0, now)
                return True
    
        def wait(self):  # 这个方法主要是提示用户等待时间的
            now = time.time()  # 获取当前时间
            return self.history[-1]+10 - now  # 最早访问的时间减去当前时间

    使用

    局部使用

     

    class TestView(APIView):
        authentication_classes = [Myauth, ]  # 用户身份验证
        permission_classes = [Permissions, ]  # 用户权限验证
        throttle_classes = [BaseThrottle, ]  # 用户访问频率限制
        
    
        def get(self, request):
            print(request.user)
            print(request.auth)
            return Response("这是会员才可以看到的画面")

    全局使用

    # 在settings.py中设置rest framework相关配置项
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],  #全局认证
        "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]  # 全局权限
        "DEFAULT_THROTTLE_CLASSES": ["app01.utils.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.py中设置rest framework相关配置项
    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.MyAuth", ],
        # "DEFAULT_PERMISSION_CLASSES": ["app01.utils.MyPermission", ]
        "DEFAULT_THROTTLE_CLASSES": ["app01.utils.VisitThrottle", ],
        "DEFAULT_THROTTLE_RATES": {
            "xxx": "5/m",
        }
    }
  • 相关阅读:
    常用设计模式
    文件上传相关报错: The current request is not a multipart request或is a MultipartResolver configured?
    Intellij IDEA 与 Gitlab 实现代码上传与下载
    Oracle两表关联,只取B表的第一条记录
    notepad++ 调整行间距
    Ubuntu18.04直接安装python3.7或者升级自带的python3.6版本之后导致终端无法打开的解决办法
    黑苹果之DELL台式机安装Mac OS X 10.13.6版本操作系统
    Windows Ping | Tracert 's Bat 脚本并行测试
    centos 7 修改 sshd | 禁止 root 登录及 sshd 端口脚本定义
    C语言中malloc函数的理解
  • 原文地址:https://www.cnblogs.com/lingcai/p/10275145.html
Copyright © 2011-2022 走看看