Autenticación de descanso: Permitir entradas desde varios equipos?
-
13-09-2019 - |
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?
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.