zoukankan      html  css  js  c++  java
  • Django drf:认证及组件、token、局部钩子源码分析

    本文目录:

    一、drf认证功能

    二、token讲解

    三、局部钩子源码分析

    一、drf认证功能

      1.认证简介:

        只有认证通过的用户才能访问指定的url地址,比如:查询课程信息,需要登录之后才能查看,没有登录则不能查看。这时候需要用到认证组件

      2.局部使用

        models层

    class User(models.Model):
        name = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
    
    
    class UserToken(models.Model):
        token = models.CharField(max_length=64)
        user = models.OneToOneField(to='User')

        新建认证类(验证通过return两个参数)

    from rest_framework.authentication import BaseAuthentication
    
    class Authlogin(BaseAuthentication):
        def authenticate(self, request):
            token = request.GET.get('token')
            res = models.UserToken.objects.filter(token=token).first()
            if res:
                # 说明这个人登录了
                # return None
                return res.user, token
            else:
                # 说明没有登录
                raise NotAuthenticated("您没有登录")

        views层

    def get_token(name):
        m = hashlib.md5(name.encode("utf-8"))
        print(m.hexdigest())
        res = m.hexdigest()
        return res
    
    
    class Login(APIView):
        #authentication_classes = []
        def post(self, request):
            response = {'status': 100, 'msg': None}
            # 把用户名和密码取到
            name = request.data.get('name')
            pwd = request.data.get('password')
            print(name, pwd)
            # 取出数据库的用户数据
            user = models.User.objects.filter(name=name, password=pwd).first()
            print(user)
            if user:
                response['msg'] = '登录成功!'
                # 随机字符串可以是用户名+当前同时生成md5
                # uuid
                token = get_token(name)
    
                # user = user 查询条件 defaults={'token':token}
                models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
                response['token'] = token
            else:
                # response['status']后面是等于号不是冒号
                response['status'] = 101
                print(response['status'])
                response['msg'] = '用户名或密码错误'
            return Response(response)
    def get_token(id,salt='123'):
        import hashlib
        md=hashlib.md5()
        md.update(bytes(str(id),encoding='utf-8'))
        md.update(bytes(salt,encoding='utf-8'))
    
        return md.hexdigest()+'|'+str(id)
    
    def check_token(token,salt='123'):
        ll=token.split('|')
        import hashlib
        md=hashlib.md5()
        md.update(bytes(ll[-1],encoding='utf-8'))
        md.update(bytes(salt,encoding='utf-8'))
        if ll[0]==md.hexdigest():
            return True
        else:
            return False
    
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            success=check_token(token)
            if success:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    class Login(APIView):
        def post(self,reuquest):
            back_msg={'status':1001,'msg':None}
            try:
                name=reuquest.data.get('name')
                pwd=reuquest.data.get('pwd')
                user=models.User.objects.filter(username=name,password=pwd).first()
                if user:
                    token=get_token(user.pk)
                    # models.UserToken.objects.update_or_create(user=user,defaults={'token':token})
                    back_msg['status']='1000'
                    back_msg['msg']='登录成功'
                    back_msg['token']=token
                else:
                    back_msg['msg'] = '用户名或密码错误'
            except Exception as e:
                back_msg['msg']=str(e)
            return Response(back_msg)
    from rest_framework.authentication import BaseAuthentication
    class TokenAuth():
        def authenticate(self, request):
            token = request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if token_obj:
                return
            else:
                raise AuthenticationFailed('认证失败')
        def authenticate_header(self,request):
            pass
    
    class Course(APIView):
        authentication_classes = [TokenAuth, ]
    
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
    不存数据库的token验证
    -{name:lqz,id:1}
     -把{name:lqz,id:1} 用我自己知道的加密方式加密之后变成了:asdfasdf
     
     -asdfasdf|{name:lqz,id:1}  当做token,发到客户端
     -以后客户端再发请求,会携带asdfasdf|{name:lqz,id:1}过来
     -服务端截取{name:lqz,id:1},再用我的加密方式加密:asdfasdf
     -拿到加密后的串:asdfasdf和请求的asdfasdf比较,如果一样
     -假设它模拟成bsdfasdf|{name:lqz,id:1,time:2019-10-13}
     bsdfasdf|{name:lqz,id:1}
     -token好处是:服务端不需要存session了
     

    总结:局部使用,只需要在试图类里加入

    authentication_classes = [TokenAuth, ]

      3.全局使用

        *一般会将继承BaseAuthentication的token类抽出来单独放在一个auth.py文件中

    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import NotAuthenticated
    from app import models
    
    class Authlogin(BaseAuthentication):
        def authenticate(self, request):
            token = request.GET.get('token')
            res = models.UserToken.objects.filter(token=token).first()
            if res:
                # 说明这个人登录了
                # return None
                return res.user, token
            else:
                # 说明没有登录
                raise NotAuthenticated("您没有登录")

        *在setting文件中配置全局认证属性

    # ["app.auth.Authlogin", ]中的Authlogin要与auth.py文件中视图类大小写一致
    REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": ["app.auth.Authlogin", ]
    }

        * 需要在login中加入局部禁用

        authentication_classes = []

    二、token讲解

       -认证功能:
          1 写一个类,继承BaseAuthentication
          2 def authenticate(self,request) ,记住传request对象
           -如果验证通过,返回None或者两个值
          3 在视图类中使用:(不要加括号)
           authentication_classes=[AuthLogin]

       -认证功能的局部配置
          -authentication_classes=[AuthLogin]
     

      -认证功能的全局配置,在settings.py中配置
          -REST_FRAMEWORK={
           "DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.AuthLogin",]
          }
     

      -全局使用的局部禁用:
          authentication_classes = []
      
       -drf内置了一些认证类(了解):
          -TokenAuthentication
          -SessionAuthentication
     

    #BaseAuthentication(规范了接口,模拟其它语言接口的概念)
    def authenticate(self, request):
        raise NotImplementedError(".authenticate() must be overridden.")
    # 如果写了一个类,继承BaseAuthentication,但是没有重写authenticate,就会抛异常

    三、局部钩子源码分析

    # 通过is_valid的父级查找到serializers

    # 找到该文件下的to_internal_value方法

     # 走完后走run_validation功能

     

  • 相关阅读:
    vim设置字体
    mplayer error opening/initializing the selected video_out (vo) device
    ubuntn MySQL安装指南
    man linux
    ubuntu中无法启用桌面效果(3D效果)几种解决方案
    man c 函数 安装 使用
    Ubuntu使用桌面小工具
    Josephus 排列问题
    Adding the PPA to Ubuntu
    Ubuntu的root密码是什么
  • 原文地址:https://www.cnblogs.com/wuzhengzheng/p/10415114.html
Copyright © 2011-2022 走看看