Django BaseAuthentication流程分析
目录
一、BaseAuthentication - 用于拦截请求,在视图函数钱执行相应认证方法
1-1 登陆相关视图函数 - 使用Token字符串存储数据库模拟session
1-2 BaseAuthentication 登陆认证 - drfAuth.py
二、认证配置 - authentication_classes
一、BaseAuthentication - 用于拦截请求,在视图函数钱执行相应认证方法
总结:
- 认证类
- 认证类必须单独存放在py文件内,若防止在view内,使用全局配置时候,无法使用
- 必须继承 BaseAuthentication
- from rest_framework.authentication import BaseAuthentication
- 认证类内必须重写 authenticate(self, request) 方法,request参数必须传入
- 若后续有其他认证类需要执行,必须返回空!!
- 若后续不无其他认证类需要执行,则返回两个值 - 对应DRF内Request对象User类内_authenticate方法执行
- 若认证失败,抛出 exceptions.APIException 异常
- from rest_framework import exceptions
- 执行认证的视图类中配置 authentication_classes = [drfAuth.LoginAuth, ]
1-1 登陆相关视图函数 - 使用Token字符串存储数据库模拟session
from rest_framework.views import APIView
import hashlib, time
from app01 import models
from django.core.exceptions import ObjectDoesNotExist
from django.http import JsonResponse
def get_token(name):
'''
将当前时间戳转化为被hash的md5字符串
- 注意:md5.update(内部必须插入bytes格式)
:param name:
:return:
'''
md5 = hashlib.md5()
md5.update(str(time.time()).encode('utf-8'))
md5.update(name.encode('utf-8'))
return md5.hexdigest()
class Login(APIView):
'''
接收对应请求发送的数据,对其中的name和pwd进行校验
- 校验通过:使用get_token(name)获取一个当前唯一的字符串作为token返回给前端,并且存入数据库中
- 校验不通过:返回错误信息
'''
def post(self, request, *args, **kwargs):
response = {'status': 100, 'msg': '登陆成功'}
name = request.data.get('name')
pwd = request.data.get('pwd')
try:
# 使用get获取表内符合对象,如不存在则报错
user = models.UserInfo.objects.get(name=name, pwd=pwd)
token = get_token(name)
# update_or_create : 表内记录的更新或创建
models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
response['token'] = token
except ObjectDoesNotExist as e:
response['status'] = 101
response['msg'] = '用户名密码错误'
except Exception as e:
# 未知错误捕获
response['status'] = 101
response['msg'] = str(e)
return JsonResponse(response, safe=False)
1-2 BaseAuthentication 登陆认证 - drfAuth.py
from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework import exceptions
import datetime
class LoginAuth(BaseAuthentication):
# authenticate必须在DRF认证内被重写,request参数必须传入
def authenticate(self, request):
'''
将获取的token去token表内进行比对,存在信息即验证通过
- 获取token表内token更新时间,若超时则验证失败重新登陆(用于数据的清理)
- 验证通过:返回空 - 表示后续仍能继续其他验证
= 验证通过:返回认证用户和当前数据记录对象 - 后续不再进行验证
- 对应DRF内Request对象User类内_authenticate方法执行
- from rest_framework.request import Request
:param request:
:return:
'''
# 数据放在header内传输,request.META获取
# meta查询key值格式:HTTP_大写字段名 例如:token - HTTP_TOKEN
token = request.META.get('HTTP_TOKEN')
# token = request.query_params.get('token')
print(token)
ret = models.UserToken.objects.filter(token=token).first()
if not ret:
# 查不到,抛异常
raise exceptions.APIException('认证失败,请重新登陆!')
t = datetime.datetime.now() - ret.token_time
print(t.total_seconds())
# 若表内登陆时间超过10min则自动清除
if t.total_seconds() > 600:
ret.delete()
raise exceptions.APIException('登陆超时,请重新登陆!')
# 查询到对应用户信息,认证通过
# 返回当前认证用户,当前token记录对象
# 返回的数据可通过 request.user, request.auth进行获取
return ret.user, ret
1-3 视图函数
from rest_framework.views import APIView
from django.http import JsonResponse
from app01 import MySerializer
from app01 import drfAuth
class Books(APIView):
# 列表中,类名不能加括号
authentication_classes = [drfAuth.LoginAuth, ]
def get(self, request, *args, **kwargs):
# 只要通过认证,就能取到当前登录用户对象
print(request.user)
response = {'status': 100, 'msg': '查询成功'}
ret = models.Book.objects.all()
book_ser = MySerializer.BookSerializer(ret, many=True)
response['data'] = book_ser.data
return JsonResponse(response, safe=False)
二、认证配置 - authentication_classes
2-1 局部配置
'''
需认证类内配置
!! 注意:可以在列表中存入多个认证类,但是存在返回值的认证类必须位于最后!!
'''
authentication_classes = [drfAuth.LoginAuth, ]
2-2 全局配置 及 局部禁用
'''
settings配置文件
所有视图内的类都会经过REST_FRAMEWORK内的认证类内认证
'''
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES':['app01.drfAuth.LoginAuth',]
}
'''
某一个视图类内禁用认证
- 认证规则首先使用当前类内的 authentication_classes 规则
- 置空表示不执行任何认证
'''
authentication_classes = []
三、相关源码分析
'''
DRF内 Request对象 User类内 _authenticate方法
'''
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
# 循环视图类内定义的所有认证类
for authenticator in self.authenticators:
try:
# 执行当前认证类,并且获取返回值
user_auth_tuple = authenticator.authenticate(self)
# 若不存在返回值,抛出异常
except exceptions.APIException:
self._not_authenticated()
raise
# 若认证类存在返回值,并且符合self.user, self.auth返回规则,return跳出循环
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号