django rest_framework 中缺少授权标头,是 apache 的错吗?

Posted

技术标签:

【中文标题】django rest_framework 中缺少授权标头,是 apache 的错吗?【英文标题】:Authorization header missing in django rest_framework, is apache to blame? 【发布时间】:2012-11-03 11:05:39 【问题描述】:

我已经设法扩展TokenAuthentication,并且在使用请求会话存储我的令牌时我有一个工作模型,但是当我尝试将Authorization 作为标头参数as described here 传递时,我注意到我的响应不带 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 将丢弃该值,但我没有了解如何允许 Authorization 标头“通过”到 Django 和 WSGIRequest。有谁知道如何解决这个问题?

我也使用 mod_auth_cas 和 mod_proxy,如果这有什么改变的话..

【问题讨论】:

【参考方案1】:

问题在于 HTTP 标头 HTTP_AUTHORIZATION 中的下划线。大多数网络服务器只是忽略带有下划线的标题。

Django 开发服务器也表现出相同的情况,省略了带有下划线的标题。

这就是Authorization2 起作用的原因。

快速解决方法是将标题中的_ 下划线替换为- 破折号,

例如。将 HTTP_AUTHORIZATION 更改为 HTTP-AUTHORIZATION

【讨论】:

我如何在 IIS 中做到这一点?【参考方案2】:

这取决于您进行了哪种 Django/Apache 部署。您需要告诉正确的 Apache 模块以允许通过“身份验证”HTTP 标头:

Apache/mod_wsgi:

WSGIPassAuthorization On

Apache/mod_fcgid:

FcgidPassHeader Authorization

换句话说:许多 Apache 模块过滤“身份验证”HTTP 标头,因此 Django 不会接收它。您必须确保您的 Django 应用程序在请求中收到它。

见: django_rest doc 和 Apache fcgid doc。

注意: 修改 Apache 配置后,您需要重新启动 apache 守护程序或告诉重新加载您的 .cgi 文件(即:touch my_site_fcgifile.fcgi)。

【讨论】:

【参考方案3】:

如果您使用的是 Apache 和 mod_wsgi,那么我在官方 Django REST 框架网站上找到了简单的解决方案

Apache mod_wsgi 特定配置

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

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

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

【讨论】:

感谢您的更新。这也适用于 Tastypie 非基于会话的身份验证。 这并不总是解决方案。如果确实使用 fcgid 在 Apache 中部署了 Django(请参阅:docs.djangoproject.com/en/1.8/howto/deployment/fastcgi/…),则必须通过添加(通常在 vhost.cof 中)告诉 mod_fcgid 传递“身份验证”标头: FcgidPassHeader Authorization 我试过这个,但它似乎不起作用。我将它添加到启用站点的 .conf 文件并重新启动 apache,但无济于事。我不断收到重定向以进行身份​​验证。有什么想法吗? 谢谢 - 这个解决方案也不是 Django 特定的,它适用于 Apache2 + uwsgi + web.py 我有一个案例,发送 Authorization Header 的移动应用程序仅在某些特定请求时才被条带化,我想知道为什么!【参考方案4】:

很抱歉在问了几分钟后回答了我自己的问题。但事实证明它毕竟是apache2!在爬网并查看了一些搜索结果后,我在评论中发现了这一点:

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

将以上几行添加到我的 conf 文件似乎解决了我所有的问题!希望这对用户有所帮助!

【讨论】:

有一张公开的票可以记录这种 apache 行为:github.com/tomchristie/django-rest-framework/issues/488 如果有人可以阐明例如。 nginx 在这方面的行为也会有所帮助。 @Tom Christie,这就是你使用 nginx 的方式:proxy_no_cache $http_pragma $http_authorization; proxy_cache_bypass $http_pragma $http_authorization; proxy_set_header HTTP_AUTHORIZATION $http_authorization; @SalvatoreIovene 我在挖掘时看到了一些注释。大概这仅适用于使用 Nginx 作为代理时。 (?) 这对我有用。请注意,我必须将重写规则放在我需要启用它的 语句中。 这可行,但显然,当没有发送授权标头时,这将创建一个空的。有没有办法在没有发送授权标头时不获取?

以上是关于django rest_framework 中缺少授权标头,是 apache 的错吗?的主要内容,如果未能解决你的问题,请参考以下文章

Django之REST_FRAMEWORK 认证组件

Django rest_framework 实用技巧

python3-开发进阶Django中序列化以及rest_framework的序列化

Django.rest_framework:如何序列化一对多?

django框架学习六:优化views.py文件,使用rest_framework中的APIVew和Response返回

Django - 如何通过 API 端点使用 rest_framework 动态地将多个对象添加到数据库中