zoukankan      html  css  js  c++  java
  • django rest framework之部分组件

    认证

      在这里,笔者将登录与认证归一起,具体代码如下

      视图函数

    def md5(user):#用账户当参数
        '''生成随机码'''
        import time
        import hashlib
    
        c_time = str(time.time())
        m = hashlib.md5(bytes(user,encoding='utf-8'))
        m.update(bytes(c_time,encoding='utf-8'))
        return m.hexdigest()
    
    
    class AuthView(APIView):
        authentication_classes = [ ]
    
        def post(self,request,*args,**kwargs):#选择method请求方式
            ret = {'code':1000,'msg':None}
            try:
                username = request._request.POST.get('username')
                password = request._request.POST.get('password')
                obj = UserInfo.objects.filter(username=username,password=password).first()
                if not obj:
                    ret['code'] = 1001
                    ret['msg'] = '账号或者密码错误!'
                token = md5(username)
                print(token)
                models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})#新建或者修改数据
                ret['msg'] = '欢迎登陆!'
                ret['token'] = token
            except Exception as e:
                pass
            return JsonResponse(ret)
    
    
    class OrderView(APIView):
    
        # authentication_classes = [Authtication,]#局部使用
        def get(self,request,*args,**kwargs):
            print(request.user)
            print(request.auth)
            ret = {'code':1000,"msg":'ok','data':None}
            try:
                ret['data'] = ORDER_DICT
            except Exception as e:
                pass
            return JsonResponse(ret)
    

      为了规范,将认证放在单独的文件下:

      

      代码如下:

    class Authtication(BaseAuthentication):#继承父类header就可以省略,因为父类里面有
        def authenticate(self,request):
            token = request._request.GET.get('token')
            token_obj = UserToken.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed('用户认证失败!')
            #drf会将两个字段的值赋值给request,以供后续使用
            return (token_obj.user,token_obj)
    
        # def authenticate_header(self,request):
        #     pass
    

      由于drf的机制,主要是列表生成式:在全局进行认证我们可以在配置文件中这么写:

    REST_FRAMEWORK = {
        "DEFAULT_AUTHENTICATION_CLASSES":["api.utils.auth.Authtication",]    #这里必须是列表,否则会报错'type' object is not iterable
    }
    

      接下来是源码的个人解读:

    用户认证源码流程
    
    1.请求进来之后,先在自己的类中寻找dispatch方法,由于我们没有自己定义,所以找到父类ApiView中的dispatch开始执行方法
    
    2.进入dispatch方法之后,对request进行封装,request不再是原生的request(如果要使用可以用request._request调用)
        封装的时候执行了一个authenticators=self.get_authenticators()方法,通过列表生成式实例化对象
    
    3.封装完request之后,开始执行initial方法,其中我们的认证是self.perform_authentication(request)这个方法实现的
    
    4.在三中的方法里面执行了request.user
    
    5.然后执行self._authenticate()方法,主要用途是循环所有的authentication对象,执行所有authentication()方法
    
    6.其实在这一步的时候我们已经可以用我们自己定义的类进行认证了
        ,执行self._authenticate()方法时,
      1.如果authenticate方法抛出异常,则执行self._not_authenticated()执行
      2.如果有返回值,必须是元祖:(request.user,request.auth)
      3.返回none,则交给下一个认证来处理 如果抛出错误,会继续抛出错误,也就是意味着会继续执行列表内的认证方法
    7.通过认证之后,开始执行我们自己的get post等方法

    梳理:

     权限

    部分代码

    单独目录下的权限

    class MyPermission(BasePermission):    #继承内置权限
        message = '您无权访问!'    #修改通知
        def has_permission(self,request,view):
            if request.user.user_type != 3:
                return False
                #提示没有权限
            return True
            #有权限

    配置文件与认证大体相同

     权限源码流程

    1.同认证一样,请求进来之后先执行dispatch方法

    2.对request进行封装

    3.继续执行initial方法

    4.对于权限继续执行check_permission方法,循环权限对象

    5.循环对象之后,执行我们自己定义的has_permission方法:通过为True,否则为False,且返回错误信息,可自己修改

     节流

      节流是为了限制用户访问次数而出现的组件

    示例代码如下:

    import time
    VISIT_RECORD = {}
    class VisitThrottle(object):
        '''节流'''
        def allow_request(self,request,view):
            remote_addr = request.META.get('REMOTE_ADDR')    #获取用户IP
            c_time = time.time()
            if remote_addr not in VISIT_RECORD:
                VISIT_RECORD[remote_addr] = [c_time,]
                return True
            history = VISIT_RECORD.get(remote_addr)
            self.history = history    #将现在的history放在self.history中,以供其他地方调用
            while history and history[-1] < c_time - 60:#大于60s的就从列表中删除
                history.pop()
    
            if len(history) < 3:
                history.insert(0,c_time)
                return True
    
        def wait(self):
            c_time = time.time()
            return 60-(c_time - self.history[-1])  #显示还有多少时间可以继续访问

    节流源码流程:

    1.请求进来之后,依旧先执行dispatch()方法

    2.对request进行封装

    3.继续执行initial方法

    4.get_throttle继续通过列表生成式实例化对象

    5.执行我们自己写的allow_request(),True则继续,False则限制

    节流的基于内置类实现的访问控制

    版本控制

    demo

    配置文件

    REST_FRAMEWORK = {
        "DEFAULT_VERSIONING_CLASS":'rest_framework.versioning.URLPathVersioning',
        "DEFAULT_VERSION":'v1',
        'ALLOWED_VERSIONS':['v1','v2'],
        "VERSION_PARAM":'version',
    }
    

    路由控制

    urlpatterns = [
        re_path(r'^api/', include('app01.urls')),
    ]
    
    urlpatterns = [
        re_path(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'),
    ]

    视图函数

    class UsersView(APIView):
        # versioning_class = ParamVersion
        def get(self,request,*args,**kwargs):
            # version = request._request.GET.get('version') 手动获取版本号
            # print(version)
            # version = request.query_params.get('version')    #通过request的方法获取版本号
    
            print(request.version)    #获取版本
            print(request.versioning_scheme)   #获取处理版本的对象
            u1 = request.versioning_scheme.reverse(viewname='uuu',request=request)    #反向生成url
            print(u1)
            return HttpResponse('Marvelous')
    

      

    源码解读

    1.请求进来之后,依旧先执行dispatch()方法

    2.对request进行封装

    3.继续执行initial方法

    4.执行determine_version方法

    5.返回版本号以及版本处理对象

    解析器

    demo

    源码解读

    1.

  • 相关阅读:
    [LeetCode] Course Schedule
    [Algorithms] Topological Sort
    [Algorithms] Graph Traversal (BFS and DFS)
    [LeetCode] One Edit Distance
    [LeetCode] Summary Ranges
    [LeetCode] Missing Ranges
    [LeetCode] Fraction to Recurring Decimal
    17.Docker之使用dockerfile创建jdk镜像
    16.Docker之使用dockerfile创建nginx镜像
    7.Docker之dockerfile指令简介
  • 原文地址:https://www.cnblogs.com/swearBM/p/10447638.html
Copyright © 2011-2022 走看看