本文目錄:
一、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)

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
# 找到該檔案下的to_internal_value方法
# 走完後走run_validation功能