2011-09-21 16 views
8

Estoy portando un proyecto de Rails 3 a 3.1. Mi sistema de autenticación se cambió fácilmente a la nueva has_secure_password en ActiveRecord. El único problema al que me estoy enfrentando es que también utilizo OmniAuth y configuré el sistema de modo que si un usuario se registra utilizando uno de los proveedores de OmniAuth, la cuenta no debería requerir una contraseña. Parece que no puedo anular la configuración de validaciones de password_digest mediante has_secure_password. ¿Hay alguna forma de desactivar esas validaciones y escribir las mías, o voy a tener que usar las funciones escritas a mano de mi versión de Rails 3 del sitio?Getting Rails 3.1's has_secure_password para funcionar bien con OmniAuth

Respuesta

5

Terminé volviendo al uso de métodos personalizados. Sin embargo, después me di cuenta de que debería haber sido capaz de utilizar una devolución de llamada before_validation para verificar las condiciones, luego, si coinciden, establezca password_digest en algo simple como '0'. De esta forma, el resumen nunca estará en blanco, pero al mismo tiempo no debería validar como una contraseña correcta, lo que hace que inicie sesión a través de OmniAuth.

No dude en corregirme si me equivoco.

+0

Voy a probar tu método, házmelo saber si encuentras una manera mejor. –

+3

Parece la solución más fácil. Acabo de establecer 'user.password_digest = SecureRandom.urlsafe_base64' en mi método' from_omniauth'. (Aunque, después de volver a leer su respuesta, supongo que no tiene que ser aleatorizado porque no se está utilizando para la autenticación). Dado que esto es mucho más rápido, me pregunto cuál es la razón para optar por la respuesta aceptada. – umezo

+0

Tienes razón. Seguí adelante y cambié la respuesta. Aunque todavía he optado por usar BCrypt directamente y escribir mis propios métodos de hash de contraseñas. Es muy fácil de hacer y aclara tus intenciones. –

4

Scott, su idea es correcta. He estado luchando con este problema en vano. Traté de anular 'has_secure_password' y simplemente no funcionará. No importa dónde metí el código.

En lugar de eso tienen la siguiente:

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 

El método apply_omniauth se llama desde el controlador cuando alguien está tratando de autenticar o regístrate.

Gracias por la idea que lo ha enganchado.

+0

Cambié la respuesta a la suya ya que proporcionó un ejemplo de código. Gracias. Supongo entonces que no le permitiría iniciar sesión en esa cuenta con ningún tipo de contraseña. –

+0

Además, ¿para qué estás usando '@ called_omniauth' exactamente? ¿No solo usar 'authentications.empty? || ! password.blank? 'en su método' password_required' es suficiente? –

+0

called_omniauth es la única forma en que su aplicación sabe que el usuario se está registrando a través de omniauth (mediante el método apply_omniauth). – chourobin

Cuestiones relacionadas