2009-12-04 9 views
6

La nostra app Rails utilizza l'autenticazione restful per la gestione di utenti/sessioni e sembra che l'accesso allo stesso account da più computer uccida la sessione sugli altri computer, eliminando così la funzione "Ricordami".Autenticazione restful: consente l'accesso da più computer?

Quindi dire che sono a casa e accedere all'app (e selezionare "Ricordami"). Poi vado in ufficio ed effettuo l'accesso (e controllo anche "Ricordami"). Quindi, quando torno a casa, torno all'app e devo effettuare nuovamente il login.

Come posso consentire l'accesso da più macchine e mantenere la funzionalità "Ricordami" che funziona su tutti loro?

risposta

9

Hai intenzione di sacrificare un po 'di sicurezza in questo modo, ma è sicuramente possibile. Ci sono due modi in cui dovresti essere in grado di farlo.

Nel primo, è possibile sostituire il metodo make_token nel modello utente. Il modello è attualmente implementato come segue.

def make_token 
    secure_digest(Time.now, (1..10).map{ rand.to_s }) 
end 

Ogni volta che un utente accede, con o senza un cookie, il metodo si chiama make_token che genera e salva un nuovo remember_token per l'utente. Se si aveva un altro valore che era unico per l'utente che non poteva essere indovinato, è possibile sostituire il metodo make_token.

def make_token 
    secure_digest(self.some_secret_constant_value) 
end 

Ciò garantirebbe che il token non cambia mai, ma sarebbe anche permettere a nessuno che ha ottenuto il token per rappresentare l'utente.

Oltre a questo, se si dà un'occhiata al metodo handle_remember_cookie! nel file authenticated_system.rb, si dovrebbe essere in grado di cambiare questo metodo per lavorare per voi.

def handle_remember_cookie!(new_cookie_flag) 
    return unless @current_<%= file_name %> 
    case 
    when valid_remember_cookie? then @current_<%= file_name %>.refresh_token # keeping same expiry date 
    when new_cookie_flag  then @current_<%= file_name %>.remember_me 
    else        @current_<%= file_name %>.forget_me 
    end 
    send_remember_cookie! 
end 

Si noterà che questo metodo chiama tre metodi nel modello di utente, refresh_token, remember_me e forget_me.

def remember_me 
    remember_me_for 2.weeks 
    end 

    def remember_me_for(time) 
    remember_me_until time.from_now.utc 
    end 

    def remember_me_until(time) 
    self.remember_token_expires_at = time 
    self.remember_token   = self.class.make_token 
    save(false) 
    end 

    # 
    # Deletes the server-side record of the authentication token. The 
    # client-side (browser cookie) and server-side (this remember_token) must 
    # always be deleted together. 
    # 
    def forget_me 
    self.remember_token_expires_at = nil 
    self.remember_token   = nil 
    save(false) 
    end 

    # refresh token (keeping same expires_at) if it exists 
    def refresh_token 
    if remember_token? 
     self.remember_token = self.class.make_token 
     save(false)  
    end 
    end 

Tutti e tre questi metodi reimpostano il token. forget_me lo imposta su nil, mentre gli altri due lo impostano sul valore restituito da make_token. È possibile eseguire l'override di questi metodi nel modello utente per impedire che reimpostino il token se esiste e non è scaduto. Questo è probabilmente l'approccio migliore, oppure potresti aggiungere qualche logica aggiuntiva al metodo handle_remember_cookie!, anche se probabilmente sarebbe più un lavoro.

Se fossi in te, sostituirò remember_me_until, forget_me e refresh_token nel modello utente. Il seguente dovrebbe funzionare.

def remember_me_until(time) 
    if remember_token? 
    # a token already exists and isn't expired, so don't bother resetting it 
    true 
    else 
    self.remember_token_expires_at = time 
    self.remember_token   = self.class.make_token 
    save(false) 
    end 
end 

# 
# Deletes the server-side record of the authentication token. The 
# client-side (browser cookie) and server-side (this remember_token) must 
# always be deleted together. 
# 
def forget_me 
    # another computer may be using the token, so don't throw it out 
    true 
end 

# refresh token (keeping same expires_at) if it exists 
def refresh_token 
    if remember_token? 
    # don't change the token, so there is nothing to save 
    true  
    end 
end 

Nota che facendo questo, stai eliminando le funzionalità che ti proteggono dal rubare token. Ma questa è una decisione sui costi che puoi prendere.

+0

Grazie mille! Quindi come funziona la funzionalità di un utente che controlla "Ricordami" adesso? Li ricorda ancora per la quantità di tempo impostata nel metodo 'remember_me'? – Shpigford

+0

Si ricorda ancora di loro per 2 settimane, come nel metodo remember_me, ma che 2 settimane inizia la prima volta che viene utilizzato il token. In altre parole, se si accede dal computer A, 10 giorni dopo il login dal computer B, 4 giorni dopo il token scade su entrambi i computer. – jcnnghm

+0

Grande. Grazie ancora per il vostro aiuto! – Shpigford

0

È possibile modificare ciò che lo remember_token deve ottenere. È possibile impostare a:

self.remember_token = encrypt("#{email}--extrajunkcharsforencryption") 

invece di

self.remember_token = encrypt("#{email}--#{remember_token_expires_at}") 

Ora non c'è nulla di computer o il tempo specifiche sul token e si può rimanere loggato da più macchine.

+0

Hmmm, a quale versione di Restful Authentication ti riferisci? Sto usando una versione abbastanza recente e 'remember_token' è impostato con una seria molto più complessa di metodi e crittografia SHA1. – Shpigford

+1

Ah, mi dispiace. Questa è una versione piuttosto vecchia che ho avuto in esecuzione per almeno un anno. Non avevo capito che era cambiato così tanto. – erik

Problemi correlati