Pregunta

Nuestra aplicación Rails utiliza autenticación de descanso para la gestión de usuarios / sesión y parece que iniciar sesión en la misma cuenta desde varios ordenadores mata la sesión en los otros equipos, matando así a la función "Recuérdame".

Así que decir que estoy en casa e iniciar sesión en la aplicación (y marca "Recuérdame"). Luego voy a la oficina y conectarse (y también comprobar "Recuérdame"). Luego, cuando vuelva a casa, volver a la aplicación e y tienen que volver a iniciar sesión.

¿Cómo puedo permitir iniciar sesión desde varias máquinas y mantener el "Remember Me" funcionalidad de trabajo a través de todos ellos?

¿Fue útil?

Solución

Lo que vas a sacrificar algo de seguridad al hacer esto, pero es definitivamente posible. Hay dos formas en que debería ser capaz de lograr esto.

En la primera, se puede reemplazar el método make_token en su modelo de usuario. El modelo se implementa actualmente como sigue.

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

Cada vez que un usuario inicia una sesión, con o sin una cookie, el método se llama make_token que genera y guarda un nuevo remember_token para el usuario. Si usted tuviera algún otro valor que era único para el usuario que no pudo ser adivinado, puede reemplazar el método make_token.

def make_token
  secure_digest(self.some_secret_constant_value)
end

Esto garantizaría que el testigo nunca cambia, sino que también permitirá a cualquier persona que tiene el token para suplantar al usuario.

Aparte de esto, si se toma una mirada en el método handle_remember_cookie! en el archivo authenticated_system.rb, usted debe ser capaz de cambiar este método funcione para usted.

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

Se dará cuenta de que este método llama tres métodos en el modelo de usuario, refresh_token, remember_me y 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

Los tres de estos métodos para reponer el token. forget_me lo establece en nil, mientras que los otros dos ajústelo en el valor devuelto por make_token. Puede anular estos métodos en el modelo de usuario, para evitar que restablecer el token si existe y no ha caducado. Esta es probablemente la mejor manera, o se podría añadir algo de lógica adicional para el método handle_remember_cookie!, sin embargo, que probablemente habría más trabajo.

Si yo fuera tú, dejaría sin efecto remember_me_until, forget_me y refresh_token en el modelo de usuario. El siguiente debería funcionar.

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

Tenga en cuenta que al hacer esto, usted está tomando un vistazo a las características que lo protegen contra el robo de fichas. Pero eso es una decisión de costes y beneficios que puede hacer.

Otros consejos

Puede cambiar lo que el remember_token es lograr esto. Usted puede configurarlo para que:

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

en lugar de

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

Ahora hay equipo o nada de tiempo específico acerca de la ficha y que puede permanecer conectado a varias máquinas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top