Django TokenAuthentication缺少“Authorization”http头

22
我正在尝试在我的一个视图中使用TokenAuthentication。 如https://www.django-rest-framework.org/api-guide/authentication/所述,我将从登录接收到的令牌作为名为“Authorization”的HTTP标头添加到我发送的请求中。
问题是在我的单元测试中身份验证失败了。 查看TokenAuthentication类后,我发现被检查的标头是'HTTP_AUTHORIZATION'而不是'Authorization'。
我正在使用的视图:
class DeviceCreate(generics.CreateAPIView):
    model = Device
    serializer_class = DeviceSerializer

    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

将标题更改为“HTTP_AUTHORIZATION”似乎可以工作,但感觉有些不对劲。我有什么遗漏吗?
2个回答

22
查看TokenAuthentication类时,我发现正在检查的标头是'HTTP_AUTHORIZATION'而不是'Authorization'。
并不完全正确,当在请求的META字典中进行查找时,实际上正在查找的标题是没有前缀'HTTP_'的,因此request.META.get('HTTP_AUTHORIZATION', '')实际上正在查找请求中的Authorization标头。
问题在于,在我的单元测试中身份验证失败了。将标头更改为'HTTP_AUTHORIZATION'似乎有效。
我还没有仔细检查测试客户端的外观,但我认为设置HTTP_AUTHORIZATION是您需要执行的操作,可以获得实际设置Authorization标头的等效内容。如果您实际上进行了http请求,您应该会发现设置auth标头正好按照您的预期工作。
请参见此处的request.META文档:https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.META 编辑:

Django文档中关于在request.META中查找标头的说明:

除了上面提到的CONTENT_LENGTH和CONTENT_TYPE之外,在请求中的任何HTTP标头都会通过将所有字符转换为大写字母,将任何连字符替换为下划线,并添加HTTP_前缀来将其转换为META键。因此,例如,名为X-Bender的标头将映射到META键HTTP_X_BENDER。

Django文档中关于使用测试客户端设置标头的说明:

但是,您可以使用关键字参数指定一些默认标头。例如,这将在每个请求中发送一个User-Agent HTTP标头:

c = Client(HTTP_USER_AGENT='Mozilla/5.0')


8

Tom的回答很好,但不够完整。

你的代码在开发环境下(使用runserver)可以正常工作,但如果你尝试在WSGI服务器上运行它(例如我的情况是Apache),服务器可能会剥离掉授权头!

你可以在Boone的博客中找到一个很好的解决方案,通过修复你的Apache配置来保留请求中的授权头并使其正常工作:

RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]

1
博客链接已失效,但那个提示救了我的心理健康。我不知道Apache/WSGI会剥离头信息! - twig
这个也帮了我大忙!Apache正剥离掉Authorization头!! - Saurav Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接