Django - DRF - BaseAuthentication 认证组件

目录

一、BaseAuthentication - 用于拦截请求,在视图函数钱执行相应认证方法

1-1 登陆相关视图函数 - 使用Token字符串存储数据库模拟session

1-2 BaseAuthentication 登陆认证 - drfAuth.py

1-3 视图函数

二、认证配置 - authentication_classes

2-1 局部配置

2-2 全局配置 及 局部禁用

三、相关源码分析


一、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()	

 

你可能感兴趣的:(DRF,Django)