2009-11-02 9 views
23

Ich pflege eine Ruby on Rails-Website und ich bin verwirrt, wie Umleitungen auf relative URLs mit dem https-Protokoll durchführen.Rails Redirect mit https

Ich kann eine Umleitung zu einer relativen URL http, zum Beispiel erfolgreich erstellen: mit dem HTTPS-Protokoll

redirect_to "/some_directory/" 

Aber ich kann nicht erkennen, wie eine Umleitung zu einer URL zu erstellen. Ich habe nur in der Lage gewesen, durch die Verwendung absolute URLS, dies zu tun, zum Beispiel:

redirect_to "https://mysite.com/some_directory/" 

Ich mag meinen Code sauber halten, und die relative URLs scheint wie eine gute Idee. Kann jemand das in Rails erreichen?

+0

Kann ich eine Klärung Ihrer Frage bekommen. Möchten Sie die Verwendung von HTTPS auf Ihrer Website oder nur für einige URLs erzwingen? Als Standard verwenden RAILS weiterhin HTTPS, wenn die aktuelle Anforderung HTTPS ist. – scottd

Antwort

8

Du bist wahrscheinlich besser dran mit ssl_requirement und Pflege nicht, wenn ein Link oder redirec t verwendet https oder verwendet es nicht. Mit ssl_requirement deklarieren Sie, welche Aktionen SSL erfordern, welche SSL-fähig sind und welche nicht, um SSL zu verwenden.

Wenn Sie irgendwo außerhalb Ihrer Rails-App umleiten, wird die Angabe des Protokolls, wie es Olly vorschlägt, funktionieren.

+14

Diese Tage sehen Sie sich "force_ssl" an, verfügbar in den Schienen 3.1 und höher. –

+3

Matt, wenn Sie Ihren Kommentar eine separate Antwort gemacht haben, würde ich dafür stimmen. – Spundun

-3

Öffnen Sie die Klasse, die redirect_to hat, und fügen Sie eine Methode redirect_to_secure_of mit einer entsprechenden Implementierung hinzu. Dann rufen:

redirect_to_secure_of "/some_directory/" 

Setzen Sie diese Methode in der lib Verzeichnis oder irgendwo nützlich.

+0

Danke, aber ich suche ein wenig mehr Details als "eine geeignete Implementierung." –

+0

Entschuldigung, ich dachte, du fragst, wie du den * rufenden * Code sauber machen kannst. – yfeldblum

-1

Relative URLs verwenden per Definition das aktuelle Protokoll und den Host. Wenn Sie das verwendete Protokoll ändern möchten, müssen Sie die absolute URL angeben. Ich würde Gerechtigkeit Rat und ein Verfahren zu schaffen, das für Sie tut:

def redirect_to_secure(relative_uri) 
    redirect_to "https://" + request.host + relative_uri 
end 
35

Die ActionController::Base#redirect_to Methode ein Options Hash nimmt, einer der Parameter, von denen :protocol ist, die Sie aufrufen können:

redirect_to :protocol => 'https://', 
      :controller => 'some_controller', 
      :action => 'index' 

Weitere Informationen zu den Optionen finden Sie in der Definition für #redirect_to und #url_for.


Alternativ und vor allem, wenn SSL ist für alle Controller-Aktionen verwendet werden, könnten Sie einen deklarativen Ansatz eine before_filter mit nehmen. In ApplicationController können Sie die folgende Methode definieren:

def redirect_to_https 
    redirect_to :protocol => "https://" unless (request.ssl? || request.local?) 
end 

Sie dann Filter in Ihrem diesen Controller hinzufügen können, welche Aktionen erfordern SSL haben, zum Beispiel:

class YourController 
    before_filter :redirect_to_https, :only => ["index", "show"] 
end 

Oder, wenn Sie SSL in Ihrer gesamten App benötigen erklären, die Filter in ApplicationController:

class ApplicationController 
    before_filter :redirect_to_https 
end 
+0

Sie können ': protocol => 'https: //' verwenden, wenn Sie einen Hash an 'redirect_to' übergeben, wenn Sie eine relative URL wie in der obigen Frage übergeben, die nicht funktioniert. Ich stimme zu, dass ein "before_filter" der bessere Weg ist, um allgemein zu gehen. –

3

Wenn Sie das Protokoll von in Controllern generierten URLs global steuern möchten, können Sie die Methode url_options in Ihrem Anwendungscontroller überschreiben.Sie könnten das Protokoll der erzeugten Urls Kraft in Abhängigkeit von den Schienen env etwa so:

def url_options 
    super 
    @_url_options.dup.tap do |options| 
     options[:protocol] = Rails.env.production? ? "https://" : "http://" 
     options.freeze 
    end 
    end 

dieses Beispiel in Schienen funktioniert 3.2.1, sie ist nicht ganz sicher, für frühere oder zukünftige Versionen.

23

Wenn Sie Ihre gesamte Anwendung über https bereitgestellt wird dann seit Rails 4.0 der beste Weg, dies zu tun ist force_ssl in der Konfigurationsdatei zu ermöglichen, etwa so:

# 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 

standardmäßig diese Option ist bereits in config/environments/production.rb in neu generierten Apps vorhanden, ist aber auskommentiert.

Wie der Kommentar sagt, wird dies nicht nur zu https umleiten, sondern setzt auch die Strict-Transport-Security Header() und stellt sicher, dass die sichere Flagge auf alle Cookies gesetzt ist. Beide Maßnahmen erhöhen die Sicherheit Ihrer Anwendung ohne wesentliche Nachteile. Es verwendet ActionDispatch:SSL.

Die HSTS-Ablaufeinstellungen sind standardmäßig auf ein Jahr eingestellt und enthalten keine Subdomains, was wahrscheinlich für die meisten Anwendungen in Ordnung ist. Sie können diese Konfiguration mit der hsts Option:

config.hsts = { 
    expires: 1.month.to_i, 
    subdomains: false, 
} 

Wenn Sie mit Rails 3 (> = 3.1) oder wollen nicht für die gesamte Anwendung https verwenden, dann können Sie verwenden die force_ssl Verfahren in einem Controller:

class SecureController < ApplicationController 
    force_ssl 
end 

das ist alles. Sie können es pro Controller einstellen, oder in Ihrem ApplicationController. Sie können HTTPS unter Verwendung der bekannten Optionen if oder unless erzwingen. Zum Beispiel:

# Only when we're not in development or tests 
force_ssl unless: -> { Rails.env.in? ['development', 'test'] } 
+0

force_ssl ist keine gute Option, wenn Sie sich hinter einem Tunnel entwickeln. Zum Beispiel können Sie in einem ngrok tls-Tunnel ein Zertifikat angeben. Dann beendet ngrok die tls-Verbindung mit dem angegebenen Zertifikat und leitet sie unverschlüsselt an Ihre App weiter (Ihre App denkt also, dass alles http ist). Dies bedeutet, dass Sie keinen Nginx-Proxy einrichten müssen und https auf Ihrer Entwicklungsumgebung ausführen müssen. –

+0

@MichaelJohnston Das ist der Grund, warum Sie 'emergen' verwenden können, um SSL nicht in dev zu erzwingen (siehe die letzte Zeile in meiner Antwort). – Carpetsmoker

2

In Schienen 4 kann man die force_ssl_redirect before_action verwenden ssl für einen einzigen Controller zu erzwingen. Bitte beachten Sie, dass Ihre Cookies mit dieser Methode nicht als sicher markiert werden und HSTS nicht verwendet wird.

+0

Können Sie bitte den letzten Satz näher erläutern? Für jemanden, der sich nicht damit auskennt, Cookies als sicher zu markieren und HSTS. –

1

Diese Antwort ist etwas tangential zur ursprünglichen Frage, aber ich nehme es auf, falls andere hier unter ähnlichen Umständen zu mir selbst kommen.

Ich hatte eine Situation, in der ich Rails verwenden musste https Proto in URL-Helfern usw., obwohl die Herkunft aller Anfragen unverschlüsselt ist (http).

nun gewöhnlich in dieser Situation (was normal ist, wenn Rails hinter einem Reverse-Proxy oder Lastenausgleich etc.), die x-forwarded-proto Header durch das Reverse-Proxy gesetzt ist oder was auch immer, so dass, obwohl Anfragen unverschlüsselt sind zwischen dem Proxy & Schienen (wahrscheinlich nicht ratsam in der Produktion übrigens) Schienen denkt, alles ist in https.

Ich musste hinter einem Ngrok TLS Tunnel laufen. Ich wollte Ngrok die Tls mit Letsencrypt-Zertifikate beenden, die ich angegeben habe. Wenn dies jedoch der Fall ist, bietet ngrok keine Möglichkeit zum Anpassen von Headern, einschließlich der Einstellung x-forwarded-proto (obwohl diese Funktion zu einem späteren Zeitpunkt geplant ist).

Die Lösung stellte sich als recht einfach heraus: Rails ist weder vom Protokoll des Ursprungs abhängig noch davon, ob x-forwarded-proto direkt gesetzt ist, sondern auf dem Rack env var rack.url_scheme. Also musste ich nur diese Rack Middleware in Entwicklung hinzufügen:

class ForceUrlScheme 
    def initialize(app) 
    @app = app 
    end 

    def call(env) 
    env['rack.url_scheme'] = 'https' 
    @app.call(env) 
    end 
end 
Verwandte Themen