如何在Token无效时让DRF不返回401错误并交由视图处理请求
问题原因
DRF默认的TokenAuthentication存在固定处理逻辑:只要请求携带了Token 前缀的Authorization请求头,就判定该请求需要走Token认证流程,一旦解析到Token值为空、不存在、对应用户失效,会直接抛出AuthenticationFailed异常,全局异常组件会直接返回401响应,完全跳过后续的权限校验、视图逻辑,即便对应视图配置了AllowAny允许匿名访问也不会执行。
解决方案
通过自定义认证类重写异常逻辑,让无效Token场景下不抛出认证异常,而是将请求标记为未认证状态,流转到后续权限、视图层自行处理。
步骤1:自定义宽松模式的Token认证类
在你的业务app下新建authentication.py文件,写入以下代码:
from rest_framework.authentication import TokenAuthentication from rest_framework.authtoken.models import Token class LenientTokenAuthentication(TokenAuthentication): def authenticate(self, request): # 提取Authorization请求头内容 auth_header = request.META.get('HTTP_AUTHORIZATION', '') # 非Token前缀的认证头直接跳过,和原生逻辑一致 if not auth_header.startswith(f'{self.keyword} '): return None # 截取Token实际值 token_key = auth_header.split(' ', 1)[1].strip() # 空Token(比如Token null场景)直接返回认证不通过,不抛错 if not token_key: return None # 尝试匹配数据库中的有效Token try: valid_token = Token.objects.select_related('user').get(key=token_key) except Token.DoesNotExist: # Token不存在直接返回认证不通过,不触发401 return None # 对应用户被禁用的场景同样不抛错,可按需调整 if not valid_token.user.is_active: return None # 只有Token完全有效时,才返回认证通过的用户对象 return (valid_token.user, valid_token)
步骤2:配置DRF使用自定义认证类
在项目settings.py中替换默认的TokenAuthentication配置:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ # 替换原生的rest_framework.authentication.TokenAuthentication 'your_app.authentication.LenientTokenAuthentication', # 保留其他需要的认证类,比如会话认证 'rest_framework.authentication.SessionAuthentication', ], # 允许匿名访问的视图需要搭配AllowAny权限使用 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ] }
补充说明
- 该认证类和原生逻辑的核心差异仅在于:非法Token场景下不再直接中断请求返回401,而是将
request.user设置为匿名用户AnonymousUser流转到后续流程,有效Token的认证逻辑和原生完全一致,不会影响正常登录用户的使用。 - 如果不需要全局生效,可以不修改全局DEFAULT_AUTHENTICATION_CLASSES配置,仅在需要放行无效Token的视图类/视图函数上单独指定
authentication_classes = [LenientTokenAuthentication]即可,其余接口仍保留原生严格校验逻辑。 - 如果业务需要区分「无Token的普通匿名请求」和「携带无效Token的请求」,可以在返回None之前给request对象打自定义标记,比如
request.invalid_token = True,后续视图逻辑中可以读取该标记做定制化处理。
内容的提问来源于stack exchange,提问作者Adilet Usonov
相关产品推荐
相关产品推荐

