Django中的fix_location_header导致错误的重定向到LOGIN_URL

时间:2016-06-30 23:40:20

标签: django django-wsgi

我正在尝试从另一个应用程序向Django发送oauth请求。 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处理程序使用名为PATH_INFO的HTTP头生成的:

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

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

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"),

在settings.py中我有:

LOGIN_URL = "/accounts/login"

现在这里是我发现有问题的Django代码行。

的django /核心/处理器/ 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)

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

那么绕过apply_reponse_fix的正确方法是什么? 1)继承并重写函数2)修改HTTP头PATH_INFO ...以某种方式3)更改响应中Location头的逻辑,使其成为带有http://前缀的完整URI,以便{{1不是没有。它们似乎都不适合我,所以我想知道我是否忽略了一个惯例。任何见解都会非常有用。

1 个答案:

答案 0 :(得分:0)

这已经解决并修复了Django 1.8的后续版本

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

只需升级到最新版本即可消失:

pip install "django>=1.8,<1.9"