在Django rest_framework中缺失授权头,是Apache的问题吗?

68

我已经成功扩展了TokenAuthentication,并在使用请求会话存储令牌时有一个工作模型。然而,当我尝试像这里描述的那样将Authorization作为标头参数传递时,我注意到我的响应没有META变量HTTP_AUTHORIZATION。我还注意到,如果我将“Authorization2”作为标头参数传递,它会显示在请求中:

{
    '_content_type': '', 
    'accepted_media_type': 'application/json', 
    '_request': <WSGIRequest
        path:/api/test_auth/,
        GET:<QueryDict: {}>,
        POST:<QueryDict: {}>,
        COOKIES:{
            'MOD_AUTH_CAS_S': 'ba90237b5b6a15017f8ca1d5ef0b95c1',
            'csrftoken': 'VswgfoOGHQmbWpCXksGUycj94XlwBwMh',
            'sessionid': 'de1f3a8eee48730dd34f6b4d41caa210'
        },
        META:{
           'DOCUMENT_ROOT': '/etc/apache2/htdocs',
           'GATEWAY_INTERFACE': 'CGI/1.1',
           'HTTPS': '1',
           'HTTP_ACCEPT': '*/*',
           'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
           'HTTP_ACCEPT_ENCODING': 'gzip,deflate,sdch',
           'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8',
           'HTTP_AUTHORIZATION2': 'Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4c',
           ...

我最初的猜测是Apache正在删除授权标头,我已经阅读了一些S/O问题,其中指出如果不匹配基本授权和身份验证,Apache将放弃该值,但我不知道如何允许授权标头“通过”到Django和WSGIRequest。有人知道如何解决这个问题吗?

我还使用mod_auth_cas和mod_proxy,如果有任何更改,请告诉我..

4个回答

86

如果您正在使用Apache和mod_wsgi,则可以在Django REST框架官方网站上找到解决此问题的简单方法

Apache mod_wsgi特定配置

请注意,如果使用mod_wsgi将应用部署到Apache,则不会默认传递授权标头到WSGI应用程序,因为假定认证将由Apache处理,而不是在应用程序级别处理。

如果您正在部署到Apache并且使用任何非会话基础的身份验证,则需要显式地配置mod_wsgi以通过所需的标头传递到应用程序。这可以通过在适当的上下文中指定WSGIPassAuthorization指令并将其设置为"On"来完成。

# this can go in either server config, virtual host, directory or .htaccess 
WSGIPassAuthorization On

2
感谢您的更新。这同样适用于Tastypie非会话基础的身份验证。 - garromark
这并不总是解决方案。如果在Apache中使用fcgid部署Django(参见:https://docs.djangoproject.com/en/1.8/howto/deployment/fastcgi/#apache-shared-hosting),你必须告诉mod_fcgid通过添加以下内容(通常在vhost.cof文件中)来传递“Authentication”头部信息:FcgidPassHeader Authorization - serfer2
谢谢 - 这个解决方案也不是特定于Django的,我在Apache2 + uwsgi + web.py上使用它成功了。 - Sergey Kudriavtsev
1
我有一个案例,其中移动应用程序发送的授权标头仅在某些特定请求中被剥离,我想知道为什么! - Karan Kumar
完美运行,谢谢 :) 在apache2 + mod_wsgi上运行Django 4.0.3,并配置ELB以使用HTTPS。来自Thunder客户端(vscode扩展)的API请求中被剥离了身份验证头。将此行添加到sites-available .conf文件中,重新启动服务器,现在它可以正常工作 :) - Ross
显示剩余3条评论

39

很抱歉在提问几分钟后自己回答了自己的问题。但是结果证明问题实际上是apache2!在搜索了一些网页并查看了一些搜索结果后,我在评论中找到了这个:

RewriteEngine on
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

将上述行添加到我的配置文件中似乎解决了我所有的问题!希望这能帮助未来的用户!


有一项开放的工单需要记录这个Apache的行为:https://github.com/tomchristie/django-rest-framework/issues/488 如果有人能解释例如Nginx在这方面的行为也会很有帮助。 - Tom Christie
@Tom Christie,以下是使用nginx的方法:proxy_no_cache $http_pragma $http_authorization; proxy_cache_bypass $http_pragma $http_authorization; proxy_set_header HTTP_AUTHORIZATION $http_authorization; - Salvatore Iovene
@SalvatoreIovene 我在查找的时候看到了一些关于这方面的注释。可能这仅适用于使用Nginx作为代理的情况,是吧?(?) - Tom Christie
这对我有用。请注意,我必须将重写规则放在<VirtualHost>语句内,以便启用它。 - Laserallan
在 IIS 中,如何做到这一点? - Quentin Merlin
显示剩余2条评论

19
这取决于您使用哪种Django/Apache部署方式。您需要告诉正确的Apache模块允许传递“身份验证”HTTP标头:
  • Apache/mod_wsgi:

    WSGIPassAuthorization On

  • Apache/mod_fcgid:

    FcgidPassHeader Authorization

换句话说:许多Apache模块过滤“身份验证”HTTP标头,因此Django将无法收到它。您必须确保在请求中收到了Django App。
请参见: django_rest docApache fcgid doc
注: 修改Apache配置后,您需要重新启动Apache服务或告诉重新加载您的.cgi文件(例如:touch my_site_fcgifile.fcgi)。

0
问题在于HTTP头中的下划线HTTP_AUTHORIZATION。大多数Web服务器都会忽略带有下划线的标头。
Django开发服务器也表现出相同的情况,省略带有下划线的标头。
这就是为什么Authorization2有效的原因。
一个快速的解决方法是用破折号-替换标头中的下划线_
例如,将HTTP_AUTHORIZATION更改为HTTP-AUTHORIZATION

我该如何在IIS中实现这个? - Quentin Merlin

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