web-dev-qa-db-fra.com

Flask url_pour générer l'URL http au lieu de https

J'utilise url_for pour générer une URL de redirection lorsqu'un utilisateur s'est déconnecté:

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

Cependant, lorsque j'ai changé la page en une connexion https, le url_for me donne toujours http.

Je voudrais demander explicitement url_for pour ajouter https au début d'une URL.

Pouvez-vous me montrer comment le changer? J'ai regardé Flask docs, sans chance.

37
Blaise

Avec Flask 0.10, il y aura une bien meilleure solution disponible que l'emballage url_for. Si vous regardez https://github.com/mitsuhiko/flask/commit/b5069d07a24a3c3a54fb056aa6f4076a0e7088c7 , un _scheme le paramètre a été ajouté. Cela signifie que vous pouvez effectuer les opérations suivantes:

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

_scheme définit le schéma d'URL, générant une URL comme https://.. au lieu de http://. Cependant, par défaut Flask ne génère que des chemins (sans hôte ni schéma), vous devrez donc inclure le _external=True pour aller de /secure_thingy à https://example.com/secure_thingy.


Cependant, pensez plutôt à rendre votre site Web uniquement en HTTPS. Il semble que vous essayez d'appliquer partiellement HTTPS pour seulement quelques routes "sécurisées", mais vous ne pouvez pas vous assurer que votre https-URL n'est pas modifiée si la page reliant à la page sécurisée n'est pas cryptée. Ceci est similaire à contenu mixte .

49
Markus Unterwaditzer

Si vous souhaitez affecter le schéma d'URL pour toutes les URL générées par le serveur (url_for et redirect), plutôt que d'avoir à définir _scheme à chaque appel, il semble que la "bonne" réponse soit d'utiliser le middleware WSGI, comme dans cet extrait: http://flask.pocoo.org/snippets/35/

( Ce Flask semble confirmer que c'est la méthode préférée.)

Fondamentalement, si votre environnement WSGI a environ['wsgi.url_scheme'] = 'https', puis url_for générera https: URL.

Je devenais http:// URL de url_for parce que mon serveur a été déployé derrière un équilibreur de charge Elastic Beanstalk, qui communique avec le serveur en HTTP standard. Ma solution (spécifique à Elastic Beanstalk) était la suivante (simplifiée à partir de l'extrait de code ci-dessus):

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)

La partie spécifique à Elastic Beanstalk est HTTP_X_FORWARDED_PROTO. D'autres environnements auraient d'autres moyens de déterminer si l'URL externe incluait https. Si vous voulez simplement toujours utiliser HTTPS, vous pouvez définir inconditionnellement environ['wsgi.url_scheme'] = 'https'.

PREFERRED_URL_SCHEME n'est pas la solution. C'est ignoré chaque fois qu'une demande est en cours .

27
aldel

J'ai essayé la réponse acceptée avec un url_for arg mais j'ai trouvé plus facile d'utiliser le PREFERRED_URL_SCHEME variable de configuration et définissez-la sur https avec:

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

puisque vous n'avez pas à l'ajouter à chaque url_for appel.

23
dajobe

Si vous accédez à votre site Web via un proxy inverse comme Nginx, alors Flask détecte correctement le schéma étant HTTP.

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

La solution la plus simple consiste à configurer votre proxy inverse pour définir le X-Forwarded-Proto entête. Flask détectera automatiquement cet en-tête et gérera le schéma en conséquence. Il y a ne explication plus détaillée dans la documentation Flask sous la section Proxy Setups =. Par exemple, si vous utilisez Nginx, vous devrez ajouter la ligne suivante dans votre bloc location.

proxy_set_header   X-Forwarded-Proto    $scheme;

Comme mentionné, si vous ne pouvez pas modifier la configuration de votre proxy, vous pouvez soit utiliser le ProxyFix werkzeug, soit créer votre propre correctif comme décrit dans la documentation: http://flask.pocoo.org/docs/ 0.12/deploying/wsgi-standalone/# proxy-setups

13
Timothée Jeannin

Définir _scheme Sur chaque appel à url_for() est extrêmement fastidieux et PREFERRED_URL_SCHEME Ne semble pas fonctionner. Cependant, le nettoyage avec le schéma supposé de la requête au niveau WSGI semble convaincre avec succès Flask pour toujours construire des 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)
8
cvrebert