天天看點

Django drf:認證及元件、token、局部鈎子源碼分析

本文目錄:

一、drf認證功能

二、token講解

三、局部鈎子源碼分析

  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)      
Django drf:認證及元件、token、局部鈎子源碼分析
Django drf:認證及元件、token、局部鈎子源碼分析
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 = []      

   -認證功能:

      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

Django drf:認證及元件、token、局部鈎子源碼分析

# 找到該檔案下的to_internal_value方法

Django drf:認證及元件、token、局部鈎子源碼分析

 # 走完後走run_validation功能

Django drf:認證及元件、token、局部鈎子源碼分析
Django drf:認證及元件、token、局部鈎子源碼分析