2011-09-21 13 views
8

Sto trasferendo un progetto da Rails 3 a 3.1. Il mio sistema di autenticazione è stato facilmente trasferito alla nuova has_secure_password in ActiveRecord. L'unico problema che sto incontrando è che utilizzo anche OmniAuth e ho il sistema configurato in modo tale che se un utente si iscrive usando uno dei provider OmniAuth l'account non dovrebbe richiedere una password. Non riesco a sovrascrivere l'impostazione di validazione password_digest di has_secure_password. Esiste comunque la possibilità di disattivare quelle convalide e scrivere le mie, o dovrò semplicemente usare le mie vecchie funzioni di bcrypt scritte dalla mia versione di Rails 3 del sito?Ottenere Rails has_secure_password 3.1 per funzionare bene con OmniAuth

risposta

5

Ho finito per tornare a utilizzare i metodi personalizzati. Tuttavia, mi sono reso conto in seguito che avrei dovuto essere in grado di utilizzare un callback before_validation per verificare le condizioni, quindi se corrispondevano impostare la password_digest su qualcosa di semplice come '0'. In questo modo il digest non sarebbe mai vuoto, ma allo stesso tempo non dovrebbe mai convalidare come password corretta, facendoli accedere tramite OmniAuth.

Sentitevi liberi di correggermi se mi sbaglio.

+0

Ho intenzione di provare il tuo metodo, fammi sapere se trovi un modo migliore. –

+3

Questa sembra la soluzione più semplice. Ho appena impostato 'user.password_digest = SecureRandom.urlsafe_base64' nel mio metodo' from_omniauth'. (Anche se, dopo aver riletto la tua risposta, suppongo che non debba essere randomizzato perché non viene usato per l'autenticazione?). Dato questo è molto più veloce - mi chiedo quale sia la logica per optare per la risposta accettata? – umezo

+0

Hai ragione. Sono andato avanti e ho cambiato la risposta. Anche se ho ancora scelto di usare BCrypt direttamente e scrivere i miei metodi di hashing della password. È troppo facile da fare e rende più chiare le tue intenzioni. –

4

Scott, la tua idea è corretta. Sono stato wrestling con questo problema senza alcun risultato. Ho provato a sovrascrivere 'has_secure_password' e semplicemente non funzionerà. Non importa dove ho bloccato il codice.

Invece ho il seguente:

class User < ActiveRecord::Base 
    has_secure_password 

    validates_presence_of :password, :on => :create, :if => :password_required 

    # Associations 
    has_many :authentications 

    # Callbacks 
    before_validation :no_password_omniauth 

    # Gets set to true if the caller is trying to authenticate with omniauth. 
    @called_omniauth = false 

    # Build new omniauth users 
    def apply_omniauth(omniauth) 
    authentications.build(
    :provider => omniauth['provider'], 
    :uid => omniauth['uid']) 
    self.first_name = omniauth['user_info']['first_name'] if self.first_name.blank? 
    self.last_name = omniauth['user_info']['last_name'] if self.last_name.blank? 
    self.email = omniauth['user_info']['email'] if omniauth['user_info']['email'] && self.email.blank? 
    @called_omniauth = true 
    end 

    def password_required 
    return false if @called_omniauth == true 
    (authentications.empty? || !password.blank?) 
    end 

    private 

    def no_password_omniauth 
    self.password_digest = 0 unless password_required 
    end 

end 

Il metodo apply_omniauth viene chiamato dal controller quando qualcuno sta cercando di autenticare o registrati.

Grazie per l'idea che l'hai inchiodato.

+0

Ho cambiato la risposta alla tua poiché hai fornito un esempio di codice. Grazie. Suppongo quindi che non ti consentirebbe di accedere a quell'account utilizzando qualsiasi tipo di password? –

+0

Inoltre, cosa stai usando '@ called_omniauth' per esattamente? Non userebbe semplicemente 'authentications.empty? || ! password.blank? nel metodo 'password_required' è sufficiente? –

+0

called_omniauth è l'unico modo in cui la tua applicazione sa che l'utente sta registrandosi tramite omniauth (con il metodo apply_omniauth). – chourobin