zoukankan      html  css  js  c++  java
  • DRF-认证 权限 频率组件

    补充

      1 认证 权限 频率组件原理基本相同

      2 认证相关:

        session cookie token 认证相关的  这里用token

        token 1 有时间限制,超时则失效 2 每次登录更换一个token

      3 访问频率限制

        1 防止同一时间多次访问的黑客攻击,增加服务器压力。

      4 我们的解析 认证 权限 频率 是在用户get post等请求之前就做好了的

      5 uuid随机数模块,uuid.uuid4()获取随机数

    认证 权限 频率组件操作流程

    认证需要建立user表和token表

    # 用户表
    class User(models.Model):
        user=models.CharField(max_length=32)
        pwd=models.CharField(max_length=32)
        type=((1,"VIP"),(2,"SVIP"),(3,"SSSVIP"))
        user_type=models.IntegerField(choices=type)
    
    
    # token表
    class UserToken(models.Model):
        user=models.OneToOneField("User")
        token=models.CharField(max_length=128)

    用户登录视图添加token

    from app01.models import User,UserToken
    
    class LoginView(APIView):
        """
        1000:成功
        1001:用户名或者密码错误
        1002:异常错误
        """
        def post(self,request):
    
           response = {"code": 1000, "msg": None, "user": None}
           try:
               print(request.data)
               user = request.data.get("user")
               pwd = request.data.get("pwd")
    
               user = User.objects.filter(user=user, pwd=pwd).first()
               import uuid
               random_str = uuid.uuid4()
               if user:
    
                   UserToken.objects.update_or_create(user=user, defaults={"token": random_str})
                   response["user"] = user.user
                   response["token"] = random_str
               else:
                   response["code"] = 1001
                   response["msg"] = "用户名或者密码错误"
    
           except Exception as e:
               response["code"]=1002
               response["msg"]=str(e)
    
    
           return Response(response)

    认证自定义的模块

    其中继承 BaseAuthentication除了类本生加的功能外还继承了header方法,如果不继承需要自己写一个header方法,否则会报错!

    from app01.models import UserToken
    from rest_framework.exceptions import AuthenticationFailed
    
    from rest_framework.authentication import BaseAuthentication
    
    class UserAuth(BaseAuthentication):
    
        def authenticate(self,request):
    
            token=request.query_params.get("token")
    
            usertoken=UserToken.objects.filter(token=token).first()
            if usertoken:
                  return usertoken.user,usertoken.token
            else:
                raise AuthenticationFailed("认证失败!")

    权限组件自定义的模块

    from rest_framework.permissions import AllowAny
    
    
    class SVIPPermission(object):
        message="您没有访问权限!"
        def has_permission(self,request,view):
            if request.user.user_type >= 2:
                return True
            return False

    频率组件自定义的模块

    以一分钟访问3次为例

    from rest_framework.throttling import BaseThrottle
    
    VISIT_RECORD={}
    class VisitThrottle(BaseThrottle):
    
        def __init__(self):
            self.history=None
    
        def allow_request(self,request,view):
            remote_addr = request.META.get('REMOTE_ADDR')
            print(remote_addr)
            import time
            ctime=time.time()
    
            if remote_addr not in VISIT_RECORD:
                VISIT_RECORD[remote_addr]=[ctime,]
                return True
    
            history=VISIT_RECORD.get(remote_addr)
            self.history=history
    
            while history and history[-1]<ctime-60:
                history.pop()
    
            if len(history)<3:
                history.insert(0,ctime)
                return True
            else:
                return False
    
        def wait(self):
            import time
            ctime=time.time()
            return 60-(ctime-self.history[-1])

    在全局中的定制

    REST_FRAMEWORK={
        # 解析器组件
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
        ),
        # 认证组件
       'DEFAULT_AUTHENTICATION_CLASSES': (
            'app01.utils.auth_class.UserAuth',
    
        ),
        # 权限组件
        'DEFAULT_PERMISSION_CLASSES': (
             'app01.utils.permission_class.SVIPPermission',
        ),
        # 频率组件  
        'DEFAULT_THROTTLE_CLASSES': (),
    }

    在局部中的定制及在视图中的使用

    # 导入自定义的认证功能类
    from app01.utils.auth_class import UserAuth
    # 导入自定义的权限功能类
    from app01.utils.permission_class import SVIPPermission
    # 导入自定义的频率功能类
    from app01.utils.throttle_classes import VisitThrottle
    
    
    from rest_framework.throttling import BaseThrottle
    class VisitThrottle(BaseThrottle):
        def allow_request(self,request,view):
             """
             限制IP每分钟访问不能超过3次
             :param request:
             :param view:
             :return:
             """
             print(self.get_ident(request))
             remote_addr = request.META.get('REMOTE_ADDR')
             print("REMOTE_ADDR",remote_addr)
             return False
    
    
    
    
    class BookView(APIView):
        # 认证
        # authentication_classes = [UserAuth]
        # 权限
        # permission_classes = [SVIPPermission]
        # 频率
        throttle_classes = [VisitThrottle]
    
        def get(self,request):
            '''
            查看所有书籍
            :param request:
            :return:
            '''
    
            print(request.user,request.auth)
    
    
    
            book_list=Book.objects.all()
            serializer=BookSerializer(book_list,many=True)
            return Response(serializer.data)
    
        def post(self,request):
            '''
            添加一条书籍
            :param request:
            :return:
            '''
            print(request.data)
    
            serializer=BookSerializer(data=request.data,many=False)
    
            if serializer.is_valid():
                serializer.save() # create操作
    
                return Response(serializer.data)
            else:
                return Response(serializer.errors)
    
    class SBookView(APIView):
    
        def get(self,request,id):
            edit_obj=Book.objects.get(pk=id)
            serializer=BookSerializer(edit_obj,many=False)
            return Response(serializer.data)
    
        def put(self,request,id):
            edit_obj = Book.objects.get(pk=id)
            serializer=BookSerializer(data=request.data,instance=edit_obj)
            if serializer.is_valid():
                serializer.save() # edit_obj.update(request.data)
                return Response(serializer.data)
            else:
                return Response(serializer.errors)
    
    
        def delete(self,request,id):
            edit_obj = Book.objects.get(pk=id).delete()
            return Response("")    

    以认证为例的源码解析

    //用户访问,当经过dispath时
    1 def dispatch(self, request, *args, **kwargs):
            self.initial(request, *args, **kwargs)
      initial()是我们的解析 认证 权限 频率功能
    2 在initial函数中
        def initial(self, request, *args, **kwargs):
            # 执行认证功能
            self.perform_authentication(request)
            # 执行权限功能
            self.check_permissions(request)
            # 执行频率功能
            self.check_throttles(request)
    3 我们走perform_authentication(request)认证功能
        def perform_authentication(self, request):
            request.user
        从这里我们要从request实例中找user方法
    4 我们通过request实例对象找到它的类中的user方法
        def dispatch(self, request, *args, **kwargs):
            request = self.initialize_request(request, *args, **kwargs)
        def initialize_request(self, request, *args, **kwargs)
            return Request(
                request,
                parsers=self.get_parsers(),
                authenticators=self.get_authenticators(),
                negotiator=self.get_content_negotiator(),
                parser_context=parser_context
            )
        class Request(object):
            def user(self):
                if not hasattr(self, '_user'):
                    with wrap_attributeerrors():
                    self._authenticate()
                return self._user
    5 在_authenticate()中:
        def _authenticate(self):
            # 和解析器一样,获得[UserAuth()] 获得顺序:当前视图类下-->全局setting-->默认default
            for authenticator in self.authenticators:
                try:
                    # 执行authenticate方法进行验证,返回元组/空 或抛出一个异常
                    user_auth_tuple = authenticator.authenticate(self)
                except exceptions.APIException:
                    self._not_authenticated()
                    raise
                # 如果返回一个元组则执行下面的语句
                if user_auth_tuple is not None:
                    self._authenticator = authenticator
                    self.user, self.auth = user_auth_tuple
                    # 这里有个坑,如果返回元组,则直接结束_authenticate函数,不继续循环了!
                    return
        这里如果不抛异常则进入下一个组件
    
    
  • 相关阅读:
    Vue使用watch监听一个对象中的属性
    小程序 显示对话框 确定-取消
    【微信小程序】 wx:if 与 hidden(隐藏元素)区别
    vue项目移植tinymce踩坑
    XMLHttpRequest.withCredentials 解决跨域请求头无Cookie的问题
    appJSON["window"]["navigationBarTextStyle"] 字段需为 black 或 white
    Java写 插入 选择 冒泡 快排
    编码表理解
    Centos yum安装java jdk1.8
    Java Hibernate和.Net EntityFramework 如何在提交事务之前 就拿到需要新增实体的Id
  • 原文地址:https://www.cnblogs.com/benson321/p/9681130.html
Copyright © 2011-2022 走看看