Redirection des Rails avec https
je maintiens un site Ruby on Rails et je ne sais pas comment effectuer des redirections vers des URLs relatives en utilisant le protocole https.
je peux créer avec succès une redirection vers une URL relative en utilisant http, par exemple:
redirect_to "/some_directory/"
mais je ne peux pas discerner comment créer une redirection vers une URL en utilisant le protocole https. Je n'ai pu le faire qu'en utilisant des URLS absolues, par exemple:
redirect_to "https://mysite.com/some_directory/"
j'aimerais garder mon code propre, et utiliser des URLs relatives semble être une bonne idée. Quelqu'un sait-il comment y parvenir dans les chemins de fer?
8 réponses
il est probablement préférable d'utiliser ssl_requirement
et de ne pas se soucier de savoir si un lien ou une redirection utilise ou non https. Avec ssl_requirement, vous déclarez quelles actions nécessitent SSL, lesquelles sont capables de SSL et lesquelles sont tenues de ne pas utiliser SSL.
si vous redirigez quelque part en dehors de votre application Rails, alors spécifier le protocole comme Olly suggère fonctionnera.
la méthode ActionController::Base#redirect_to
prend un hachage d'options, dont l'un des paramètres est :protocol
qui vous permet d'appeler:
redirect_to :protocol => 'https://',
:controller => 'some_controller',
:action => 'index'
voir la définition de #redirect_to
et #url_for
pour plus d'informations sur les options.
alternativement, et surtout si SSL doit être utilisé pour toutes vos actions de controller, vous pourriez prendre un plus déclaratif approche avec un before_filter
. Dans ApplicationController
, vous pouvez définir la méthode suivante:
def redirect_to_https
redirect_to :protocol => "https://" unless (request.ssl? || request.local?)
end
vous pouvez alors ajouter des filtres dans vos contrôleurs qui ont des actions nécessitant SSL, E. g:
class YourController
before_filter :redirect_to_https, :only => ["index", "show"]
end
ou, si vous avez besoin de SSL sur l'ensemble de votre application, déclarez le filtre dans ApplicationController
:
class ApplicationController
before_filter :redirect_to_https
end
si vous voulez que votre demande entière soit servie sur https puis depuis Rails 4.0 la meilleure façon de faire ceci est d'activer force_ssl
dans le fichier de configuration comme ceci:
# config/environments/production.rb
Rails.application.configure do
# [..]
# Force all access to the app over SSL, use Strict-Transport-Security,
# and use secure cookies.
config.force_ssl = true
end
Par défaut, cette option est déjà présente dans config/environments/production.rb
dans de nouvelles applications, mais est commenté.
comme le dit le commentaire, cela ne redirigera pas seulement vers https, mais Strict-Transport-Security
en-tête ( HSTS ) et s'assure que le drapeau sécurisé est placé sur tous les cookies. Ces deux mesures augmentent la sécurité de votre application sans inconvénients majeurs. Il utilise ActionDispatch:SSL
.
les paramètres d'expiration HSTS sont définis à un an par défaut et n'inclut pas les sous-domaines, ce qui est probablement bien pour la plupart des applications. Vous pouvez le configurer avec l'option hsts
:
config.hsts = {
expires: 1.month.to_i,
subdomains: false,
}
si vous utilisez Rails 3 (>=3.1) ou si vous ne voulez pas utiliser https pour toute l'application, alors vous pouvez utiliser la méthode force_ssl
dans un contrôleur:
class SecureController < ApplicationController
force_ssl
end
C'est tout. Vous pouvez le régler par controller, ou dans votre ApplicationController
. Vous pouvez forcer https conditionnellement en utilisant les options familières if
ou unless
; par exemple:
# Only when we're not in development or tests
force_ssl unless: -> { Rails.env.in? ['development', 'test'] }
si vous voulez contrôler globalement le protocole des urls générées dans les controllers, vous pouvez outrepasser la méthode url_options dans votre controller application. Vous pouvez forcer le protocole des urls générées en fonction des rails env comme suit:
def url_options
super
@_url_options.dup.tap do |options|
options[:protocol] = Rails.env.production? ? "https://" : "http://"
options.freeze
end
end
cet exemple fonctionne dans les rails 3.2.1, Je ne suis pas exactement sûr pour les versions précédentes ou futures.
cette réponse est quelque peu tangente à la question initiale, mais je l'enregistre au cas où d'autres finissent ici dans des circonstances similaires à moi-même.
j'ai eu une situation où je devais avoir des Rails utiliser https
proto dans les helpers url, etc. même si l'origine de toutes les requêtes n'est pas cryptée ( http
).
maintenant, habituellement dans cette situation (ce qui est normal lorsque les Rails sont derrière un mandataire inversé ou un équilibreur de charge, etc.), le x-forwarded-proto
l'en-tête est défini par le proxy inverse ou autre, donc même si les requêtes sont non cryptées entre le proxy & rails (probablement déconseillé dans la production d'ailleurs) rails pense que tout est dans https
.
j'avais besoin de courir derrière un tunnel ngrok tls. Je voulais que ngrok résilie le tls avec les certificats letsencrypt que j'avais spécifiés. Cependant, quand il le fait, ngrok n'offre pas la possibilité de personnaliser les en-têtes, y compris le réglage x-forwarded-proto
(bien que ce fonctionnalité est prévue à un certain moment dans l'avenir).
la solution s'est avérée très simple: les Rails ne dépendent pas du protocole de l'origine ou si x-forwarded-proto
est placé directement, mais sur le Rack env var rack.url_scheme
. Donc j'ai juste besoin d'ajouter ce Rack middleware en développement:
class ForceUrlScheme
def initialize(app)
@app = app
end
def call(env)
env['rack.url_scheme'] = 'https'
@app.call(env)
end
end
URLs relatives, par définition, utiliser le protocole et l'hôte actuels. Si vous souhaitez modifier le protocole utilisé, vous devez fournir l'URL absolue. Je suivrais les conseils de Justice et créerais une méthode qui fait cela pour vous:
def redirect_to_secure(relative_uri)
redirect_to "https://" + request.host + relative_uri
end
ouvrir la classe qui a redirect_to
et ajouter une méthode redirect_to_secure_of
avec une implémentation appropriée. Puis appelez:
redirect_to_secure_of "/some_directory/"
mettez cette méthode dans le répertoire lib
ou quelque part utile.