认证是比较通用的功能,基本上大多数系统都需要认证功能,
它的流程如下:
请求进来后,先到dispatch方法,dispatch有个initialize_request方法,它会对Request对象进行封装,包括request, authenticators.
将旧的request封装为新的_request, authenticators则通过get_authenticators()方法获取,get_authenticator()方法获取authentication_class,即返回一个认证类的对象列表。initialize_request之后还有一个inital方法,它调用perform_autentication方法,它执行request.user,取user属性,调用authenticator的authenticate方法,该方法返回一个由user对象,auth组成的元组,如果没通过验证,用户被设置为匿名用户,auth被设置为None
restframework中的认证也是分为局部和全局配置两种,
restframework有三种认证方式:
class SessionAuthentication(BaseAuthentication):
def enforce_csrf(self, request: Request) -> None: ...
class TokenAuthentication(BaseAuthentication):
keyword: str = ...
model: Optional[Type[Model]] = ...
def get_model(self) -> Type[Model]: ...
def authenticate_credentials(self, key: str) -> Tuple[Any, Any]: ...
class RemoteUserAuthentication(BaseAuthentication):
header: str = ...
这里用的TokenAuthentication,即当用户登陆后生成一个token保存到数据库,下次请求来的时候就可以验证token查询是否登陆
class LuffyAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
token = request.query_params.get('token')
if not token:
return (None,None)
user_object = models.UserInfo.objects.filter(token=token).first()
if user_object:
return (user_object,token)
return (None,None)
如果验证通过即将use对象和token返回,否则返回None,这样在request中即保存了user对象的信息,需要取用时只需要调用request.user属性即可。
多数情况下,验证是需要全局配置的,settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": ['api.extension.auth.LuffyAuthentication', ],
}
但是,像登陆视图,就是用来登陆的,如果此时也进行验证,将会进入死循环,所以需要将它排除在验证之外,这就需要将login视图中的authentication_class指定为空列表。
class LoginView(APIView):
"""
登录接口
"""
authentication_classes = []
def post(self, request, *args, **kwargs):
user_object = models.UserInfo.objects.filter(**request.data).first()
if not user_object:
return Response('登录失败')
random_string = str(uuid.uuid4())
user_object.token = random_string
user_object.save()
return Response(random_string)
同样的道理,认证是需要全局使用的功能,所以个别不需要的情况下是使用“排除”的方法,即将其认证类指定为空。