2012-04-18 19 views
28

Ho sviluppato le mie app per binari mantenendole il più modulari possibile. Sto cercando di implementare diverse parti sotto come servizi.Autenticazione delle rotaie tra app/server

Di 'un esempio di Facebook:
a) Un MainApp che permette all'utente di avere un muro, i messaggi, ecc
b) Un PhotoApp che memorizza le foto, permette all'utente di vedere le sue foto , ecc. Questa è un'app standalone che avrà un'API REST che può essere utilizzata anche da MainApp.

Stavo pensando di utilizzare OAuth come soluzione Single Sign On (come in questo tutorial http://blog.joshsoftware.com/2010/12/16/multiple-applications-with-devise-omniauth-and-single-sign-on/) in cui ogni app verrà autorizzata tramite OAuth e otterrà l'accesso alla sessione utente corrente in base al cookie.

Prima domanda: È una soluzione valida?

Seconda domanda: voglio essere in grado di chiamare il PhotoApp API dal MainApp server di (non dal browser dell'utente). Come funzionerebbe l'autenticazione in questa situazione?

Terza domanda: Come questo lavoro se dire che ho avuto un servizio che utilizza node.js?

+0

Ci sono alcuni [server Oauth] (http://www.knight.io/categories/oauth-servers-ruby) che potrebbero aiutare nell'implementazione di tale scenario. –

risposta

20

Sì, SSO con OAuth è una soluzione valida, ma non è la più semplice. Quando si crea qualcosa di nuovo, OAuth 2.0 è la strada da percorrere. Gli standard OAuth coprono molto terreno.

Il vantaggio principale di OAuth è che è che consente agli utenti di accedere alle app di terze parti al proprio account senza rivelare la propria password al terzo utente. Se non stai fornendo seriamente tale interoperabilità, OAuth è probabilmente eccessivo.

Data la complessità, mi offrono una coppia diversa di soluzioni:

per Single Sign On

Il trucco è quello di condividere l'ID del cookie di sessione tra gli host all'interno del dominio & di utilizzare una sessione condivisa store (come ActiveRecordStore o un archivio basato sulla cache.)

Ogni app Rails ha un "segreto" che viene utilizzato per firmare i cookie. Nelle app Rails più recenti si trova in /config/initializers/secret_token.rb. Imposta lo stesso token segreto in ogni applicazione.

Quindi, configurare la sessione per consentire l'accesso da tutti i sottodomini:

AppName::Application.config.session_store :active_record_store, :key => '_app_name_session', :domain => :all 

Per API interno invita

Utilizzare un buon segreto condiviso per l'autenticazione su connessioni HTTPS. Passa il segreto nel valore dell'intestazione "Autorizzazione".

È possibile utilizzare facilmente il segreto condiviso con altre architetture (come node.js). Assicurati di utilizzare sempre HTTPS, altrimenti il ​​segreto condiviso potrebbe essere annusato sulla rete.

+1

La condivisione di un ID sessione sembra un buon inizio per SSO, ma si ferma qui. C'è una grande quantità di dettagli di implementazione lasciati qui. Come si autentica un'app durante l'accesso? In che modo l'app apprende le funzionalità di un utente che ha effettuato l'accesso? – Fitzsimmons

+1

Sì, c'è molto da progettare quando si implementa una soluzione SSO completa. Creare un servizio di autenticazione centralizzato è probabilmente un buon inizio, ma è al di là di una risposta su StackOverflow ... probabilmente più come un libro di O'Reilly. – Mars

+0

Ciò presuppone che tutti i domini condividano un dominio/sottodominio comune. Che ne pensi di diversi tld? – lukad

3

Recentemente ho avuto un problema simile a quello di voler condividere i dati di sessione tra Rails e un'app Erlang. La mia soluzione era scrivere una classe Rack::Session::Abstract::ID che memorizzava le sessioni in Redis come hash vaule. Non chiama il numero Marshal.dump nei tipi String. Ciò consente alle applicazioni non-ruby di utilizzare alcuni dei valori di sessione se hanno lo session_id.

require 'rack/session/abstract/id' 

class MaybeMarshalRedisSession < Rack::Session::Abstract::ID 

    def initialize(app, options = {}) 
    @redis = options.delete(:redis) || Redis.current 
    @expiry = options[:expire_after] ||= (60 * 60 * 24) 
    @prefix = options[:key] || 'rack.session' 
    @session_key = "#{@prefix}:%s" 
    super 
    end 

    def get_session(env, sid) 
    sid ||= generate_sid 
    session = @redis.hgetall(@session_key % sid) 
    session.each_pair do |key, value| 
     session[key] = begin 
     Marshal.load(value) 
     rescue TypeError 
     value 
     end 
    end 

    [sid, session] 
    end 

    def set_session(env, sid, session, options={}) 
    @redis.multi do 
     session.each_pair do |key, value| 
     # keep string values bare so other languages can read them 
     value = value.is_a?(String) ? value : Marshal.dump(value) 
     @redis.hset(@session_key % sid, key, value) 
     end 
     @redis.expire(@session_key % sid, @expiry) 
    end 

    sid 
    end 

    def destroy_session(env, sid, option={}) 
    @redis.del(@session_key % sid) 
    generate_sid unless options[:drop] 
    end 

end 

È possibile utilizzare questo dalle rotaie con:

MyApp::Application.config.session_store MaybeMarshalRedisSession 

Da rack con:

use MaybeMarshalRedisSession 

E da altrove con:

redis.hgetall("rack.session:#{session_id}") 

Se si desidera chiamare PhotoApp dalla tua MainApp o Node.js yo puoi fare una richiesta HTTP che includa il cookie di sessione dell'utente.

3

Si potrebbe guardare una soluzione di Architettura orientata ai servizi proposta da Jeremy Green a Octolabs durante il RailsConf del 2014.

Il post sul blog con tutte le risorse (pronti contro termine, demo, ecc) si trova qui: http://www.octolabs.com/so-auth

E il video che spiega tutto è qui: http://www.youtube.com/watch?v=L1B_HpCW8bs

Questa centralizzato SSO non è un compito semplice, ma Jeremy ha fatto un ottimo lavoro parlando di Service Oriented Architecture e condividendo esattamente come si potrebbe mettere insieme questo sistema.

Problemi correlati