Подтвердить что ты не робот

Flask url_for генерации http-URL вместо https

Я использую url_for для создания URL перенаправления, когда пользователь вышел из системы:

return redirect(url_for('.index', _external=True))

Однако, когда я изменил страницу на соединение https, url_for все еще дает мне http.

Я хотел бы явно попросить url_for добавить https в начале URL.

Можете ли вы указать мне, как это изменить? Я посмотрел на документы Flask, без удачи.

4b9b3361

Ответ 1

С Flask 0.10 будет гораздо лучшее решение, чем перенос url_for. Если вы посмотрите на https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7, был _scheme параметр _scheme. Это означает, что вы можете сделать следующее:

url_for('secure_thingy',
        _external=True,
        _scheme='https',
        viewarg1=1, ...)

_scheme устанавливает схему URL, генерируя URL как https://.. вместо http://. Однако по умолчанию Flask генерирует только пути (без хоста или схемы), поэтому вам нужно будет включить _external=True чтобы перейти от /secure_thingy к https://example.com/secure_thingy.


Тем не менее, рассмотрите возможность сделать свой сайт только для HTTPS. Кажется, вы пытаетесь частично применить HTTPS только для нескольких "безопасных" маршрутов, но вы не можете гарантировать, что ваш https-URL не изменится, если страница, ссылающаяся на защищенную страницу, не зашифрована. Это похоже на смешанный контент.

Ответ 2

Если вы хотите повлиять на схему URL для всех URL-адресов, созданных сервером (url_for и redirect), вместо того, чтобы устанавливать _scheme для каждого вызова, кажется, что "правильный" ответ заключается в использовании WSGI, как в этом фрагменте: http://flask.pocoo.org/snippets/35/

(Эта ошибка Flask, похоже, подтверждает, что это предпочтительный вариант.)

В принципе, если ваша среда WSGI имеет environ['wsgi.url_scheme'] = 'https', то url_for будет генерировать URL https:.

Я получал http:// URL-адреса от url_for, потому что мой сервер был развернут за балансиром нагрузки Elastic Beanstalk, который связывается с сервером в обычном HTTP-сообщении. Мое решение (специфичное для Elastic Beanstalk) было таким (упрощено из приведенного выше фрагмента):

class ReverseProxied(object):
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        scheme = environ.get('HTTP_X_FORWARDED_PROTO')
        if scheme:
            environ['wsgi.url_scheme'] = scheme
        return self.app(environ, start_response)

app = Flask(__name__)
app.wsgi_app = ReverseProxied(app.wsgi_app)

Эластичная составляющая этого компонента - HTTP_X_FORWARDED_PROTO. В других средах есть другие способы определения, включен ли внешний URL-адрес https. Если вы просто хотите всегда использовать HTTPS, вы можете безоговорочно установить environ['wsgi.url_scheme'] = 'https'.

PREFERRED_URL_SCHEME - это не способ сделать это. Он игнорируется всякий раз, когда выполняется запрос.

Ответ 3

Я попробовал принятый ответ с аргументом url_for, но мне было проще использовать конфигурационную конфигурацию PREFERRED_URL_SCHEME и установить ее в https с помощью:

app.config.update(dict(
  PREFERRED_URL_SCHEME = 'https'
))

так как вам не нужно добавлять его к каждому вызову url_for.

Ответ 4

Если вы обращаетесь к своему веб-сайту через обратный прокси-сервер, такой как Nginx, Flask правильно определяет схему, используя HTTP.

Browser -----HTTPS----> Reverse proxy -----HTTP----> Flask

Самое простое решение - настроить обратный прокси-сервер для установки заголовка X-Forwarded-Proto. Flask автоматически обнаружит этот заголовок и будет соответственно управлять схемой. Более подробное объяснение приведено в документации Flask в разделе "Настройки прокси". Например, если вы используете Nginx, вам нужно будет добавить следующую строку в свой блок location.

proxy_set_header   X-Forwarded-Proto    $scheme;

Как уже упоминалось, если вы не можете изменить конфигурацию вашего прокси, вы можете использовать werkzeug ProxyFix или создать собственное исправление, как описано в документации: http://flask.pocoo.org/docs/0.12/deploying/WSGI-автономный/# прокси-расстановок

Ответ 5

Настройка _scheme для каждого вызова url_for() крайне утомительна, а PREFERRED_URL_SCHEME, похоже, не работает. Тем не менее, ошибка в том, что предполагаемая схема запроса на уровне WSGI, похоже, успешно убеждает Flask всегда создавать URL-адреса HTTPS:

def _force_https(app):
    def wrapper(environ, start_response):
        environ['wsgi.url_scheme'] = 'https'
        return app(environ, start_response)
    return wrapper

app = Flask(...)

app = _force_https(app)