认证

前言

用户验证用户是否合法登陆。

部分内容在DRF视图的使用及源码流程分析讲解,建议先看讲解视图的这篇文章。

使用流程

认证使用的方法流程如下:

  1. 自定义认证类,继承BaseAuthentication,并且覆写其authenticate方法。不继承BaseAuthentication也可以,但认证类中必须声明authenticateauthenticate_header两个方法。
  2. 当认证通过后应该返回两个值(一个元组),并且第一个值会传递给request.user这个属性中,第二个值将会传递给request.auth这个属性中。
  3. 如果认证失败,则抛出异常APIException或者AuthenticationFailed,它会自动捕获并返回。
  4. 当前认证类设置是全局使用还是局部使用。

自定义认证类:

完成1、2、3步,异常统一返回AuthenticationFailed

import jwt
from jwt import exceptions
import rest_framework.exceptions as rest_exception
from rest_framework.authentication import BaseAuthentication
from rest_framework import status
from app1.models import Login
from libs.TokenManager import SALT class MyAuthentication(BaseAuthentication): def authenticate(self, request):
token = request.META.get("HTTP_TOKEN") # 在请求头中设置token值,获取的是HTTP_TOKEN
if not token:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="请在请求头中设置token值!")
try: # 解析token
verified_payload = jwt.decode(token, SALT, "HS256")
user_id, username = verified_payload["user_id"], verified_payload["username"]
user = Login.objects.filter(user=user_id, token=token).first()
if user:
return user_id, username
else:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在!")
except exceptions.ExpiredSignatureError:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="token已经失效!")
except jwt.DecodeError:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="token认证失败!")
except jwt.InvalidTokenError:
raise rest_exception.AuthenticationFailed(code=status.HTTP_401_UNAUTHORIZED, detail="token非法!")

第4步:

局部认证:

在一个需要认证的CBV里面,添加authentication_classes类属性。如:

class UserAPIView(GenericAPIView, ListModelMixin):
authentication_classes = [MyAuthentication]
queryset = User.objects
serializer_class = UserSerializer

全局认证:

settings.py里面设置:

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ["libs.MyAuth.MyAuthentication"]
}

在源码分析部分,大家将会明白为何这样设置。

源码分析

认证的执行,是发生在dispatch函数的过程中。

值得注意的是,封装request的时候,我们的指定的认证类也会一起封装在新的request里面。

接下来看看get_authenticators的执行。

使用列表生成式挨个实例化了每个authentication_classes里面的认证类。而authentication_classes读取了我们自定义的认证类。

注:

如果是局部认证,那么就是我们直接给authentication_classes赋值

如果是全局认证,那么就是读取我们settings中的DEFAULT_AUTHENTICATION_CLASSES配置项。

之后,在initial函数中,执行了三大验证,其中就有认证。

而认证直接执行了request.user,它其实是一个被@property装饰的方法。

接下来的操作都是在rest_framework.request模块里面。新封装的request就是这下面的Request类的实例。

当没有_user属性的时候,说明还未认证,则会执行 _authenticate() 方法

  • 认证成功,返回元组。
  • 认证失败,执行_not_authenticated

补充

最后,一个问题,当配置了全局认证以后,之后每个接口的访问都要执行认证,而有的借口并不需要认证或者认证的类不一样(如登陆接口),该怎么办呢?

其实很好办,全局设置以后并不影响局部设置的生效,因为局部设置的优先级大于全局设置,就比如对于登陆接口来说,我们只需要在登陆接口CBV中设置authentication_classes为空就可以了。如果有特殊需要,也可以指定其他认证类。

class LoginAPIView(APIView):
authentication_classes = []

最新文章

  1. 编写高质量代码:改善Java程序的151个建议(第8章:多线程和并发___建议126~128)
  2. APNS 服务推送通知
  3. saltstack实战4--综合练习4
  4. Basic MSI silent install
  5. plsql中文乱码问题(显示问号)
  6. 传说中的WCF(1):这东西难学吗?
  7. JavaScript巧学巧用
  8. python对mysql数据库操作的三种不同方式
  9. 菜鸟的Xamarin.Forms前行之路——按钮的按下抬起事件的监控(可扩展至其他事件)
  10. TCP那些事儿(上)
  11. 写给 Android 应用工程师的 Binder 原理剖析
  12. 1、Flutter_初体验_创建第一个应用_AndroidStudio_windows
  13. SQL Server中如何定位Row Lock锁定哪一行数据
  14. Ionic-轮播图ion-slide-box
  15. @Transactional导致AbstractRoutingDataSource动态数据源无法切换的解决办法
  16. BZOJ 1040 骑士 基环树 树形DP
  17. Socket详解-Linux Socket编程(不限Linux)
  18. nginx中获取真实ip(转)
  19. django系列8.5--使用装饰器(视图函数中)实现用户登录状态检验
  20. IDEA 提示找不到 javax 等 tomcat 的相关包

热门文章

  1. Ubuntu22.04 安装配置流水账
  2. 使用nginx反向代理RabbitMQ的web界面
  3. 使用logstash同步Mysql数据表到ES的一点感悟
  4. EFCore分表实现
  5. Notebook交互式完成目标检测任务
  6. 编写一个应用程序,在主类Test1类中,创建两个链表List<E>对象,分别存储通过键盘输入的字符串内容
  7. vue2双向绑定原理:深入响应式原理defineProperty、watcher、get、set
  8. Docker | Compose创建mysql容器
  9. 7 步保障 Kubernetes 集群安全
  10. clang在编译时指定目标文件所需的最低macOS版本