如何在 Django 设置中指定显式主机名?

How to specify explicit host name in Django settings?

我正在开发一个通过多个 Docker 容器运行的 Django 项目,Django 站点本身是一个 Nginx 容器将请求转发到的中间件。为了测试 Nginx 容器的端口 80 映射到 8080。因此我去 http://localhost:8080/ 并查看 Django 网站。

我遇到的问题是重定向 URL(由 social-auth-app-django 包为 Google 登录构建)使用 http://localhost 作为基础而不是 http://localhost:8080.

设置 LOGIN_REDIRECT_URL 不是我要找的,因为它发生在 身份验证成功之后。

我试过 SOCIAL_AUTH_LOGIN_REDIRECT_URL,它是 mentioned somewhere,但那是旧版本,似乎不再执行任何操作。

由于 Django 对所有绝对 URL 使用 build_absolute_uri,因此必须有一种方法来覆盖基 URL and/or host?

TL;DR = Nginx 没有 Docker-mapped 端口的概念,需要 hard-coded.

类似问题:https://serverfault.com/questions/577370/how-can-i-use-environment-variables-in-nginx-conf

Django 要求 HTTP 请求 headers 包含主机所需的信息(下面的代码片段)。这种情况需要从Nginx传入:

location / {
    proxy_pass http://web:7000;
    proxy_set_header Host $host:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

注意端口的不幸 hard-coding:$host:8080。 "outer" 问题是 Nginx 容器的端口使用 Docker 映射到 8080 (-p 80:8080) 因此它 不知道 它是实际上 运行 在端口 8080 上; Nginx 在端口 80 上将自己检测为 运行。

SOCIAL_AUTH_LOGIN_REDIRECT_URL 的 Django 设置,但像这样指定它:

SOCIAL_AUTH_LOGIN_REDIRECT_URL = 'http://localhost:8080/complete/google-oauth2/'

尝试通过 Google 进行身份验证时导致此情况发生:

AuthMissingParameter at /complete/google-oauth2/

Missing needed parameter state

Request Method: GET

Request URL: http://localhost:8080/complete/google-oauth2/

Django Version: 2.1.5

Exception Type: AuthMissingParameter

Exception Value:

Missing needed parameter state

Exception Location: /usr/local/lib/python3.6/site-packages/social_core/backends/oauth.py in validate_state, line 88

Python Executable: /usr/local/bin/python

Python Version: 3.6.10

因此我目前唯一的解决方案是在构建 Docker 图像时将端口烘焙到 Nginx 配置中。

Django 2.1.5版获取主机代码:

def _get_raw_host(self):
    """
    Return the HTTP host using the environment or request headers. Skip
    allowed hosts protection, so may return an insecure host.
    """
    # We try three options, in order of decreasing preference.
    if settings.USE_X_FORWARDED_HOST and (
            'HTTP_X_FORWARDED_HOST' in self.META):
        host = self.META['HTTP_X_FORWARDED_HOST']
    elif 'HTTP_HOST' in self.META:
        host = self.META['HTTP_HOST']
    else:
        # Reconstruct the host using the algorithm from PEP 333.
        host = self.META['SERVER_NAME']
        server_port = self.get_port()
        if server_port != ('443' if self.is_secure() else '80'):
            host = '%s:%s' % (host, server_port)
    return host