Django服务端设置Authorization Header无效,求可行实现方案
你遇到的问题核心是认证时机不对:Django的认证中间件(比如你用的TokenAuthentication)是在视图函数执行前就完成运行的。当你在视图里修改request.META['HTTP_AUTHORIZATION']时,认证流程早就结束了,request.user已经被初始化完成,所以这个修改对认证结果完全没有影响。
下面给你两种可行的解决方案,根据你的场景灵活选择:
方案一:自定义认证中间件(推荐)
这种方式最优雅,把认证逻辑放到了请求处理的正确阶段——视图执行前,和Django默认的认证流程完全对齐,适合全局复用。
步骤1:编写中间件
在你的app目录下创建middleware.py文件,添加如下代码:
from django.utils.deprecation import MiddlewareMixin class CookieTokenMiddleware(MiddlewareMixin): def process_request(self, request): # 从HttpOnly Cookie中取出token token = request.COOKIES.get('token') # 如果存在token且当前请求还没有Authorization头,就注入 if token and not request.META.get('HTTP_AUTHORIZATION'): request.META['HTTP_AUTHORIZATION'] = f'Token {token}'
步骤2:注册中间件
在项目的settings.py中,将这个中间件加到MIDDLEWARE列表里,位置要放在TokenAuthentication对应的中间件之前(通常紧跟在AuthenticationMiddleware之后):
MIDDLEWARE = [ # ... 其他系统中间件 ... 'django.contrib.auth.middleware.AuthenticationMiddleware', 'your_app_name.middleware.CookieTokenMiddleware', # 替换成你的app名称 'rest_framework.authentication.TokenAuthentication', # ... 其他中间件 ... ]
步骤3:简化视图代码
现在你可以删掉视图里手动修改request.META的代码了,因为中间件已经提前帮你完成了头注入,认证流程会自动生效:
@api_view(['POST']) @permission_classes([IsAuthenticated]) def createView(request, *args, **kwargs): print(request.user) # 这里已经是认证后的用户对象 print(request.headers) serializer = TweetPostSerializer(data=request.data) if serializer.is_valid(): serializer.save(user=request.user) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
方案二:在视图中手动认证
如果你不想修改全局中间件,也可以在单个视图里手动触发认证逻辑,直接更新request.user。
修改你的视图代码如下:
from rest_framework.authentication import TokenAuthentication from rest_framework.exceptions import AuthenticationFailed @api_view(['POST']) # 这里可以暂时去掉@permission_classes([IsAuthenticated]),或者后续手动检查用户状态 def createView(request, *args, **kwargs): token = request.COOKIES.get('token') if not token: return Response({"detail": "Token未在Cookie中找到"}, status=status.HTTP_401_UNAUTHORIZED) # 手动调用TokenAuthentication的认证方法 auth_handler = TokenAuthentication() try: user, auth_token = auth_handler.authenticate_credentials(token) # 替换request的用户和认证信息 request.user = user request.auth = auth_token except AuthenticationFailed: return Response({"detail": "无效的Token"}, status=status.HTTP_401_UNAUTHORIZED) # 此时request.user已经是认证通过的用户 print(request.user) print(request.headers) serializer = TweetPostSerializer(data=request.data) if serializer.is_valid(): serializer.save(user=request.user) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
这种方式的缺点是需要在每个需要认证的视图里重复写认证逻辑,适合临时或特定视图的场景。
再理清楚为什么原来的方法无效
Django的请求处理流程是中间件层 → 视图层,认证中间件属于中间件环节,会优先完成用户认证并设置request.user。你在视图里修改request.META的时候,认证已经结束了,所以这个修改无法回溯影响已经完成的认证结果。
内容的提问来源于stack exchange,提问作者Harrison Austin Osagiede

