用户验证用户是否合法登录。
部份内容在DRF视图的使用及源码流程分析讲解,建议先看讲解视图的这篇文章。html
认证使用的方法流程以下:python
BaseAuthentication
,而且覆写其authenticate
方法。不继承BaseAuthentication
也能够,但认证类中必须声明authenticate
和authenticate_header
两个方法。request.user
这个属性中,第二个值将会传递给request.auth
这个属性中。APIException
或者AuthenticationFailed
,它会自动捕获并返回。自定义认证类:app
完成一、二、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步:源码分析
局部认证:spa
在一个须要认证的CBV里面,添加authentication_classes
类属性。如:3d
class UserAPIView(GenericAPIView, ListModelMixin): authentication_classes = [MyAuthentication] queryset = User.objects serializer_class = UserSerializer
全局认证:rest
在settings.py
里面设置:code
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["libs.MyAuth.MyAuthentication"] }
在源码分析部分,你们将会明白为什么这样设置。jwt
认证的执行,是发生在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 = []