Django自定义中间件排除指定路径配置及request.auth报错排查
问题根因
'WSGIRequest' object has no attribute 'auth' 报错由执行时机错位直接导致:
- Django中间件的
process_view钩子固定在路由匹配完成后、视图函数执行前触发,时机早于视图内部所有逻辑。 - 如果使用DRF搭配JWT认证,
request.auth属性是DRFAPIView在dispatch流程中执行认证组件时才挂载到请求对象上的,process_view执行阶段视图尚未启动,认证逻辑根本没有运行,自然无法获取auth属性。 - 即使是Django原生视图场景,只要auth属性的挂载逻辑晚于
process_view执行时机,都会触发同类报错。
规范的中间件豁免实现方案
该方案和Django原生csrf_exempt实现逻辑一致,无硬编码路由,和路由配置完全解耦,维护性更强。
第一步:实现豁免标记装饰器
# 新建common/decorators.py from functools import wraps def token_response_exempt(view_func): """标记视图不需要走ExtendTokenResponse中间件逻辑""" wrapped = wraps(view_func)(view_func) wrapped.token_response_exempt = True return wrapped
第二步:调整中间件逻辑
不要把token校验逻辑放到process_view中,改回__call__方法内、视图执行完成的阶段执行,这时候request.auth已经完成挂载,同时可通过路由匹配结果读取视图的豁免标记:
# your_project/middleware.py from django.utils.deprecation import MiddlewareMixin class ExtendTokenResponse(MiddlewareMixin): def _check_exempt(self, request): """校验当前请求匹配的视图是否标记了豁免""" resolver_match = getattr(request, 'resolver_match', None) if not resolver_match: return False view_func = resolver_match.func # 兼容类视图 view_class = getattr(view_func, 'view_class', None) if view_class: if getattr(view_class, 'token_response_exempt', False): return True # 兼容函数视图、类视图单独方法标记 return getattr(view_func, 'token_response_exempt', False) def __call__(self, request): # 先走完整的请求处理链,等所有认证逻辑执行完成 response = self.get_response(request) # 豁免视图直接返回,不执行token处理逻辑 if self._check_exempt(request): return response # 这时候request.auth已经挂载完成,可安全执行token校验、刷新逻辑 if hasattr(request, 'auth') and request.auth: # 此处写入原有的token过期判断、刷新、响应头追加新token的业务逻辑 pass return response
第三步:给需要豁免的视图加标记
- 函数视图直接加装饰器即可:
from common.decorators import token_response_exempt from django.http import JsonResponse @token_response_exempt def logout(request): return JsonResponse({"code": 0, "msg": "退出成功"})
- 类视图使用
method_decorator标记:
from django.utils.decorators import method_decorator from django.views import View from common.decorators import token_response_exempt @method_decorator(token_response_exempt, name='dispatch') class LoginView(View): def post(self, request): return JsonResponse({"code": 0, "msg": "登录成功"})
注意事项
- 不推荐硬编码
request.path做匹配的核心原因是,后续如果调整路由前缀、增加多语言路径、做版本迭代时,硬编码规则很容易遗漏失效,视图标记的方式和路由完全解耦,不会出现这类问题。 - 如果确实需要把token校验逻辑放到视图执行前(比如需要提前拦截过期token请求,不让请求打到视图层),必须保证你的
ExtendTokenResponse中间件在MIDDLEWARE配置列表中排在所有挂载request.auth的中间件之后;如果是DRF项目,因为认证逻辑在视图层执行,这种场景不适合用中间件做前置校验,建议把逻辑下沉到DRF认证类或权限类中实现。
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

