如何判断Django Rest Framework中哪个认证类先验证成功?
问题描述
我的Django Rest Framework认证类配置如下:
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.SessionAuthentication", "MyCustomAuthClass", ], ... }
根据DRF官方文档:
REST framework会尝试使用列表中的每个类进行认证,并使用第一个成功认证的类的返回值设置request.user和request.auth。
我需要在特定视图端点中区分**第三个认证类(MyCustomAuthClass)**是否是成功完成认证的那个类。目前我通过重复执行认证逻辑来判断,但这种方式冗余且性能低下:
def get(self, request): if ( not TokenAuthentication().authenticate(request) and not SessionAuthentication().authenticate(request) and MyCustomAuthClass().authenticate(request) ): # 针对MyCustomAuthClass的处理逻辑 else: # 其他逻辑
请问有没有更优的实现方式?还是当前方案已经是最佳选择?
更优实现方案
完全不需要重复执行认证流程,以下是几种高效的解决方案:
方案1:在认证类中给request添加标记
修改自定义认证类,在认证成功时给request对象添加专属标识:
from rest_framework.authentication import BaseAuthentication class MyCustomAuthClass(BaseAuthentication): def authenticate(self, request): # 原有认证逻辑,这里示例用占位符表示 user, auth = self._custom_authenticate_logic(request) if user is not None: # 标记当前认证成功的类名 request.authenticated_by = self.__class__.__name__ return (user, auth) return None
对于内置的TokenAuthentication和SessionAuthentication,我们可以通过子类继承添加标记:
from rest_framework.authentication import TokenAuthentication, SessionAuthentication class MarkedTokenAuthentication(TokenAuthentication): def authenticate(self, request): result = super().authenticate(request) if result is not None: request.authenticated_by = self.__class__.__name__ return result class MarkedSessionAuthentication(SessionAuthentication): def authenticate(self, request): result = super().authenticate(request) if result is not None: request.authenticated_by = self.__class__.__name__ return result
然后更新settings中的认证类配置为这些带标记的子类:
REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "yourapp.auth.MarkedTokenAuthentication", "yourapp.auth.MarkedSessionAuthentication", "yourapp.auth.MyCustomAuthClass", ], ... }
之后在视图里直接判断标记即可:
def get(self, request): if getattr(request, 'authenticated_by', None) == 'MyCustomAuthClass': # 执行MyCustomAuthClass对应的逻辑 else: # 其他认证方式的处理逻辑
方案2:重写视图的initial方法追踪认证类
如果不想修改全局认证类,可以在目标视图中重写initial方法,仅执行一次认证流程来记录成功的类:
from rest_framework.views import APIView from rest_framework import exceptions class TargetView(APIView): def initial(self, request, *args, **kwargs): super().initial(request, *args, **kwargs) # 遍历认证类,找到第一个成功认证的类 for auth_class in self.authentication_classes: auth_instance = auth_class() try: result = auth_instance.authenticate(request) if result is not None: request.authenticated_by = auth_class.__name__ break except exceptions.AuthenticationFailed: continue def get(self, request): if getattr(request, 'authenticated_by', None) == 'MyCustomAuthClass': # 对应逻辑处理 else: # 其他逻辑
方案3:利用request.auth的类型区分(按需使用)
如果MyCustomAuthClass返回的auth是自定义类型,可以直接通过类型判断:
def get(self, request): if isinstance(request.auth, YourCustomAuthToken): # 说明是MyCustomAuthClass认证成功 else: # 其他认证方式的情况
总结
方案1是最推荐的方式:一次性在认证类中添加标记,后续所有视图都可以直接使用,无额外性能开销。方案2适合不想修改全局认证配置的场景,仅针对单个视图处理。方案3是最简洁的,但仅适用于自定义认证的auth对象有独特类型的情况。
内容的提问来源于stack exchange,提问作者Johnny Metz
相关产品推荐
相关产品推荐

