2012-06-24 3 views
18

Ich arbeite an einer App, wo Server und der api-konsumierenden Client unter verschiedenen Domänen residieren, also möchte ich CORS verwenden. Um dies zu tun, muß ich entsprechende HTTP-Header in der Server-Antwort festgelegt:So senden Sie CORS-Header mit Devise, wenn Benutzer nicht autorisiert (401 Antwort)

def cors_set_access_control_headers 
    headers['Access-Control-Allow-Origin'] = 'http://localhost' 
    headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS' 
    headers['Access-Control-Allow-Headers'] = '*, X-Requested-With, X-Prototype-Version, X-CSRF-Token, Content-Type' 
    headers['Access-Control-Max-Age'] = "1728000" 
end 

diese Methode als before_filter in ApplicationController verwendet wird.

Für einige Ressourcen muss der Benutzer authentifiziert und autorisiert werden. Anfragen werden über XHR/Ajax erledigt. Wenn der Benutzer also nicht authentifiziert wird, sendet Devise eine 401-Antwort an den Client, anstatt auf eine Anmeldeseite umzuleiten. Aber der Filter zum Setzen der CORS-Header wird nicht für diese Antwort verwendet. Daher wird die 401-Antwort nicht an den Client gesendet. Ich möchte die 401-Antwort im Client erfassen und verwenden.

Derzeit bin ich eine Abhilfe, indem nicht die Devise Authentifizierungsmethoden verwenden, sondern eine benutzerdefinierte Auth-Schnipsel:

def authenticate_cors_user 
    if request.xhr? && !user_signed_in? 
    error = { :error => "You must be logged in." } 
    render params[:format].to_sym => error, :status => 401 
    end 
end 

Dies als before_filter in ApplicationController auch gesetzt ist. Auf diese Weise wird der Filter zum Setzen von CORS-Headern ausgelöst und alles funktioniert einwandfrei.

Ich würde lieber das Standardverhalten von Devise verwenden, aber die CORS-Header müssten in der 401-Antwort gesetzt werden. Wie macht man das? Muss ich dafür warden konfigurieren?

Wie können die CORS-Header für die von Devise generierte 401-Antwort festgelegt werden, anstatt eine eigene Antwort zu erstellen?

+0

Noch ich keine Lösung dafür. Um etwas mehr Kontext zu geben, schaue in meinem Blogpost darüber nach, wie ich das benutze: http://nils-blum-oesteth.net/cors-api-with-oauth2-authentication-using-rails-and-angularjs –

Antwort

21

ich erfolgreich die Rack-cors gem https://github.com/cyu/rack-cors und skizzierte meine Erfahrung auf my blog.

Punchline: Middleware, um Geben Sie so vor warden cors Handler:

config.middleware.insert_before Warden::Manager, Rack::Cors 
+0

Ihr Ansatz funktioniert gut, danke! Seltsamerweise dauerte es einige Zeit und einige zusätzliche Recherchen, um zu erkennen, dass ich wirklich nur eine Zeile Code in der Konfiguration ändern musste, um 'Devise' und' Rack-Cors' zusammen zu arbeiten. –

+0

Hey @ Digger69. Hatten Sie Probleme mit anderen Ausnahmen? Zum Beispiel: wenn ich eine Ausnahme in meiner Aktion "Def Index"; "Fehler" melden; Ende - Rails gibt die CORS-Header (Rack-Cors) nicht zurück. Funktioniert es für Sie? –

+4

PS: Sie könnten auch 'config.middleware.insert 0, Rack :: Cors 'verwenden, um zu garantieren, dass' Rack :: Cors' vor jeder anderen möglichen Middleware eingefügt wird. –

0

Wir mochte CORS Header im Allgemeinen nicht. Wir bevorzugen die Verwendung von HAProxy für Umleitungen.

Mit HAProxy können Sie alle Anfragen, die auf website.com/api/ eingehen, so einrichten, dass sie intern auf Ihren Rails-Rechner umgeleitet werden.

frontend main *:80 
    acl api  path_beg -i /api 
    acl app  path_beg -i /app 
backend app_backend 
    reqrep ^([^\ ]*)\ /app/(.*) \1\ /\2 
    balance roundrobin 
    server app_files smartphoneapp.localhost:8000 
backend api_backend 
    reqrep ^([^\ ]*)\ /api/(.*) \1\ /\2 
    balance roundrobin 
    server app_api localhost:3000 
+0

CORS könnte mit einem Proxy umgangen werden, sicher. Aber trotzdem muss es einen Weg geben, dies gut mit Devise/warden zu vereinbaren, denke ich. –

+0

Werfen Sie einen Blick auf diesen Artikel: http://www.tsheffler.com/blog/?p=428 – Hendrik