Django中的fix_location_header导致错误的重定向到LOGIN_URL [英] fix_location_header in Django causes wrong redirection to LOGIN_URL

查看:385
本文介绍了Django中的fix_location_header导致错误的重定向到LOGIN_URL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从另一个应用程序发送一个请求到Django。 Django托管在8000端口,应用程序在8080上。这是从应用程序调用的URL:

  http:// localhost :8000 / o / authorize /?client_id = MM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG& response_type = token& redirect_url = http:// localhost:8080 / auth / add_token 

这将被重定向到一个错误的位置:

  http://192.168.56.101:8000 /o/authorize/accounts/login/?next=/o/authorize/%3Fclient_id%3DMM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG%26response_type%3Dtoken%26redirect_url%3Dhttp%3A//192.168.56.101%3A8080/auth/add_token 

当我希望它没有前缀 / o / authorize 由WSGI处理程序使用HTTP标头生成的名为 PATH_INFO

  http://192.168.56.101:8000/accounts/login/?next=/o/autho rize /%3Fclient_id%3DMM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG%26response_type%3Dtoken%26redirect_url%3Dhttp%3A // 192.168.56.101%3A8080 / auth / add_token 

我在urls.py中有以下路由,如果不是我正在面对的怪异重定向,它们可以正常工作。

  url(r'^ o /',include('oauth2_provider.urls',namespace ='oauth2_provider')),
#OAuth用户信息
url(r'^ o / api / get_userinfo / $',oauth2.GetuserInfoView.as_view(),name =get-userinfo),

在settings.py中,我有:

  LOGIN_URL =/ accounts / login

现在,我发现有问题的Django代码行。



django / core / handlers / base.py:220

  #应用响应中间件,无论响应
为self._response_middleware中的中间件_方法:
response = middleware_method(请求,响应)
#如果响应中间件返回None(一个常见错误),则投诉。
如果响应为None:
raise ValueError(
%s.process_response没有返回
HttpResponse对象,它返回None
% (middleware_method .__ self __.__ class __.__ name__))
response = self.apply_response_fixes(请求,响应)
#^^^ ------------这将导致fix_location_header为调用。

django / http / utils.py



<$

确保我们在
响应中的任何位置标题中始终使用绝对URI。由RFC 2616第14.30节要求

构建响应对象的代码可以自由地插入相对路径,如
此函数将它们转换为绝对路径

如果位置响应:
响应['位置'] = request.build_absolute_uri(响应['位置'])
返回响应
pre>

django / request.py

  def build_absolute_uri(self,位置=无):

从位置和
中可用的变量构建一个绝对URI,如果没有指定location,绝对URI为
建立在``request.get_full_path()``。无论如何,如果位置是
的绝对值,它只是c转换为符合RFC 3987标准的URI,并返回
,如果位置是相对的或是方案相对的(即
``// example.com /``),则它被链接到一个基本URL从
请求变量。

如果位置为无:
#为
#边缘情况使路径以'//'开头的绝对url(但无纹理和无域) 。
location ='//%s'%self.get_full_path()
bits = urlsplit(location)
如果没有(bits.scheme和bits.netloc):
current_uri ='{scheme}:// {host} {path}'.format(scheme = self.scheme,
host = self.get_host(),
path = self.path)
#^^^ ---我发现有问题的位置URL形成逻辑
#使用提供的位置加入构造的URL,
#允许提供的location应用查询字符串到
#基本路径以及覆盖主机,如果它以//
位置= urljoin(current_uri,位置)开头
返回iri_to_uri(位置)

我包含源文件中的注释,因此读者可以知道他们的用例。



那么绕过 apply_reponse_fix 的正确方法是什么? 1)继承和重写函数2)修改HTTP头PATH_INFO ...不知何故3)更改位置头的逻辑,以便它是一个完整的URI,具有 http:// 前缀,以便 bits.scheme 不是无。他们似乎都不是一个正确的解决方案,所以我想知道我是否忽视了一个惯例。任何见解将非常有帮助。

解决方案

这已经解决和修复了更高版本的Django 1.8



fix_location_header已删除: https://code.djangoproject.com/ticket/ 23960



只需升级到最新版本即可使用:

  pip installdjango> = 1.8,< 1.9


I am trying to send an oauth request from another application to Django. Django is hosted on 8000 port and the application on 8080. Here is the URL called from the application:

http://localhost:8000/o/authorize/?client_id=MM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG&response_type=token&redirect_url=http://localhost:8080/auth/add_token

This will get redirected to a wrong location:

http://192.168.56.101:8000/o/authorize/accounts/login/?next=/o/authorize/%3Fclient_id%3DMM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG%26response_type%3Dtoken%26redirect_url%3Dhttp%3A//192.168.56.101%3A8080/auth/add_token

when I expect it to be without the prefix /o/authorize which is is generated by WSGI handler using HTTP header called PATH_INFO:

http://192.168.56.101:8000/accounts/login/?next=/o/authorize/%3Fclient_id%3DMM8i27ROetg3OQv60tDcJwp7JKXi28FqkuQgetyG%26response_type%3Dtoken%26redirect_url%3Dhttp%3A//192.168.56.101%3A8080/auth/add_token

I have following routes in urls.py and they work properly if it is not for the weird redirection I am facing.

url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
# OAuth User Info
url(r'^o/api/get_userinfo/$', oauth2.GetuserInfoView.as_view(), name="get-userinfo"),

In settings.py I have:

LOGIN_URL = "/accounts/login"

Now here are the lines of Django code that I find problematic.

django/core/handlers/base.py:220

        # Apply response middleware, regardless of the response
        for middleware_method in self._response_middleware:
            response = middleware_method(request, response)
            # Complain if the response middleware returned None (a common error).
            if response is None:
                raise ValueError(
                    "%s.process_response didn't return an "
                    "HttpResponse object. It returned None instead."
                    % (middleware_method.__self__.__class__.__name__))
        response = self.apply_response_fixes(request, response)
                   # ^^^------------this will lead to fix_location_header being called.

django/http/utils.py

def fix_location_header(request, response):
    """
    Ensures that we always use an absolute URI in any location header in the
    response. This is required by RFC 2616, section 14.30.

    Code constructing response objects is free to insert relative paths, as
    this function converts them to absolute paths.
    """
    if 'Location' in response:
        response['Location'] = request.build_absolute_uri(response['Location'])
    return response

django/request.py

def build_absolute_uri(self, location=None):
    """
    Builds an absolute URI from the location and the variables available in
    this request. If no ``location`` is specified, the absolute URI is
    built on ``request.get_full_path()``. Anyway, if the location is
    absolute, it is simply converted to an RFC 3987 compliant URI and
    returned and if location is relative or is scheme-relative (i.e.,
    ``//example.com/``), it is urljoined to a base URL constructed from the
    request variables.
    """
    if location is None:
        # Make it an absolute url (but schemeless and domainless) for the
        # edge case that the path starts with '//'.
        location = '//%s' % self.get_full_path()
    bits = urlsplit(location)
    if not (bits.scheme and bits.netloc):
        current_uri = '{scheme}://{host}{path}'.format(scheme=self.scheme,
                                                       host=self.get_host(),
                                                       path=self.path)
        # ^^^---The location URL forming logic that I find problematic.
        # Join the constructed URL with the provided location, which will
        # allow the provided ``location`` to apply query strings to the
        # base path as well as override the host, if it begins with //
        location = urljoin(current_uri, location)
    return iri_to_uri(location)

I included the comments from the source file so the reader could know there are use cases for them.

So what is the proper way of getting around apply_reponse_fix? 1) inherit and rewrite the function 2) modify HTTP header PATH_INFO... somehow 3) change the logic for Location header in response so that it is a full URI with http:// prefix so that bits.scheme is not None. None of them seem like a proper fix for me, so I am wondering if I overlooked a convention. Any insight will be very helpful.

解决方案

This has been already addressed and fixed later version of Django 1.8

fix_location_header is removed: https://code.djangoproject.com/ticket/23960

Just upgrading to the latest version made it go away:

pip install "django>=1.8,<1.9"

这篇关于Django中的fix_location_header导致错误的重定向到LOGIN_URL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆