DRF认证流程及源码分析
认证
前言
用户验证用户是否合法登陆。
部分内容在DRF视图的使用及源码流程分析讲解,建议先看讲解视图的这篇文章。
使用流程
认证使用的方法流程如下:
- 自定义认证类,继承
BaseAuthentication
,并且覆写其authenticate
方法。不继承BaseAuthentication
也可以,但认证类中必须声明authenticate
和authenticate_header
两个方法。 - 当认证通过后应该返回两个值(一个元组),并且第一个值会传递给
request.user
这个属性中,第二个值将会传递给request.auth
这个属性中。 - 如果认证失败,则抛出异常
APIException
或者AuthenticationFailed
,它会自动捕获并返回。 - 当前认证类设置是全局使用还是局部使用。
自定义认证类:
完成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 = []
最新文章
- 编写高质量代码:改善Java程序的151个建议(第8章:多线程和并发___建议126~128)
- APNS 服务推送通知
- saltstack实战4--综合练习4
- Basic MSI silent install
- plsql中文乱码问题(显示问号)
- 传说中的WCF(1):这东西难学吗?
- JavaScript巧学巧用
- python对mysql数据库操作的三种不同方式
- 菜鸟的Xamarin.Forms前行之路——按钮的按下抬起事件的监控(可扩展至其他事件)
- TCP那些事儿(上)
- 写给 Android 应用工程师的 Binder 原理剖析
- 1、Flutter_初体验_创建第一个应用_AndroidStudio_windows
- SQL Server中如何定位Row Lock锁定哪一行数据
- Ionic-轮播图ion-slide-box
- @Transactional导致AbstractRoutingDataSource动态数据源无法切换的解决办法
- BZOJ 1040 骑士 基环树 树形DP
- Socket详解-Linux Socket编程(不限Linux)
- nginx中获取真实ip(转)
- django系列8.5--使用装饰器(视图函数中)实现用户登录状态检验
- IDEA 提示找不到 javax 等 tomcat 的相关包
热门文章
- Ubuntu22.04 安装配置流水账
- 使用nginx反向代理RabbitMQ的web界面
- 使用logstash同步Mysql数据表到ES的一点感悟
- EFCore分表实现
- Notebook交互式完成目标检测任务
- 编写一个应用程序,在主类Test1类中,创建两个链表List<;E>;对象,分别存储通过键盘输入的字符串内容
- vue2双向绑定原理:深入响应式原理defineProperty、watcher、get、set
- Docker | Compose创建mysql容器
- 7 步保障 Kubernetes 集群安全
- clang在编译时指定目标文件所需的最低macOS版本