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 的错吗?的主要内容,如果未能解决你的问题,请参考以下文章
python3-开发进阶Django中序列化以及rest_framework的序列化
Django.rest_framework:如何序列化一对多?
django框架学习六:优化views.py文件,使用rest_framework中的APIVew和Response返回