Django 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

  1. from rest_framework.views import APIView
  2. import hashlib, time
  3. from app01 import models
  4. from django.core.exceptions import ObjectDoesNotExist
  5. from django.http import JsonResponse
  6. def get_token(name):
  7. '''
  8. 将当前时间戳转化为被hash的md5字符串
  9. - 注意:md5.update(内部必须插入bytes格式)
  10. :param name:
  11. :return:
  12. '''
  13. md5 = hashlib.md5()
  14. md5.update(str(time.time()).encode('utf-8'))
  15. md5.update(name.encode('utf-8'))
  16. return md5.hexdigest()
  17. class Login(APIView):
  18. '''
  19. 接收对应请求发送的数据,对其中的name和pwd进行校验
  20. - 校验通过:使用get_token(name)获取一个当前唯一的字符串作为token返回给前端,并且存入数据库中
  21. - 校验不通过:返回错误信息
  22. '''
  23. def post(self, request, *args, **kwargs):
  24. response = {'status': 100, 'msg': '登陆成功'}
  25. name = request.data.get('name')
  26. pwd = request.data.get('pwd')
  27. try:
  28. # 使用get获取表内符合对象,如不存在则报错
  29. user = models.UserInfo.objects.get(name=name, pwd=pwd)
  30. token = get_token(name)
  31. # update_or_create : 表内记录的更新或创建
  32. models.UserToken.objects.update_or_create(user=user, defaults={'token': token})
  33. response['token'] = token
  34. except ObjectDoesNotExist as e:
  35. response['status'] = 101
  36. response['msg'] = '用户名密码错误'
  37. except Exception as e:
  38. # 未知错误捕获
  39. response['status'] = 101
  40. response['msg'] = str(e)
  41. return JsonResponse(response, safe=False)

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

  1. from rest_framework.authentication import BaseAuthentication
  2. from app01 import models
  3. from rest_framework import exceptions
  4. import datetime
  5. class LoginAuth(BaseAuthentication):
  6. # authenticate必须在DRF认证内被重写,request参数必须传入
  7. def authenticate(self, request):
  8. '''
  9. 将获取的token去token表内进行比对,存在信息即验证通过
  10. - 获取token表内token更新时间,若超时则验证失败重新登陆(用于数据的清理)
  11. - 验证通过:返回空 - 表示后续仍能继续其他验证
  12. = 验证通过:返回认证用户和当前数据记录对象 - 后续不再进行验证
  13. - 对应DRF内Request对象User类内_authenticate方法执行
  14. - from rest_framework.request import Request
  15. :param request:
  16. :return:
  17. '''
  18. # 数据放在header内传输,request.META获取
  19. # meta查询key值格式:HTTP_大写字段名 例如:token - HTTP_TOKEN
  20. token = request.META.get('HTTP_TOKEN')
  21. # token = request.query_params.get('token')
  22. print(token)
  23. ret = models.UserToken.objects.filter(token=token).first()
  24. if not ret:
  25. # 查不到,抛异常
  26. raise exceptions.APIException('认证失败,请重新登陆!')
  27. t = datetime.datetime.now() - ret.token_time
  28. print(t.total_seconds())
  29. # 若表内登陆时间超过10min则自动清除
  30. if t.total_seconds() > 600:
  31. ret.delete()
  32. raise exceptions.APIException('登陆超时,请重新登陆!')
  33. # 查询到对应用户信息,认证通过
  34. # 返回当前认证用户,当前token记录对象
  35. # 返回的数据可通过 request.user, request.auth进行获取
  36. return ret.user, ret

1-3 视图函数

  1. from rest_framework.views import APIView
  2. from django.http import JsonResponse
  3. from app01 import MySerializer
  4. from app01 import drfAuth
  5. class Books(APIView):
  6. # 列表中,类名不能加括号
  7. authentication_classes = [drfAuth.LoginAuth, ]
  8. def get(self, request, *args, **kwargs):
  9. # 只要通过认证,就能取到当前登录用户对象
  10. print(request.user)
  11. response = {'status': 100, 'msg': '查询成功'}
  12. ret = models.Book.objects.all()
  13. book_ser = MySerializer.BookSerializer(ret, many=True)
  14. response['data'] = book_ser.data
  15. return JsonResponse(response, safe=False)

二、认证配置 - authentication_classes

2-1 局部配置

  1. '''
  2. 需认证类内配置
  3. !! 注意:可以在列表中存入多个认证类,但是存在返回值的认证类必须位于最后!!
  4. '''
  5. authentication_classes = [drfAuth.LoginAuth, ]

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

  1. '''
  2. settings配置文件
  3. 所有视图内的类都会经过REST_FRAMEWORK内的认证类内认证
  4. '''
  5. REST_FRAMEWORK={
  6. 'DEFAULT_AUTHENTICATION_CLASSES':['app01.drfAuth.LoginAuth',]
  7. }
  8. '''
  9. 某一个视图类内禁用认证
  10. - 认证规则首先使用当前类内的 authentication_classes 规则
  11. - 置空表示不执行任何认证
  12. '''
  13. authentication_classes = []

三、相关源码分析

  1. '''
  2. DRF内 Request对象 User类内 _authenticate方法
  3. '''
  4. def _authenticate(self):
  5. """
  6. Attempt to authenticate the request using each authentication instance
  7. in turn.
  8. """
  9. # 循环视图类内定义的所有认证类
  10. for authenticator in self.authenticators:
  11. try:
  12. # 执行当前认证类,并且获取返回值
  13. user_auth_tuple = authenticator.authenticate(self)
  14. # 若不存在返回值,抛出异常
  15. except exceptions.APIException:
  16. self._not_authenticated()
  17. raise
  18. # 若认证类存在返回值,并且符合self.user, self.auth返回规则,return跳出循环
  19. if user_auth_tuple is not None:
  20. self._authenticator = authenticator
  21. self.user, self.auth = user_auth_tuple
  22. return
  23. self._not_authenticated()

 

posted @ 2023-02-24 19:01  Python喵  阅读(121)  评论(0编辑  收藏  举报