Vas a sacrificar algo de seguridad al hacer esto, pero definitivamente es posible. Hay dos formas en que deberías poder lograr esto.
En la primera, puede anular el método make_token en su modelo de usuario. El modelo se implementa actualmente de la siguiente manera.
def make_token
secure_digest(Time.now, (1..10).map{ rand.to_s })
end
Cada vez que un usuario inicia una sesión en, con o sin una cookie, el método de make_token
se llama que genera y guarda un nuevo remember_token
para el usuario. Si tenía algún otro valor que fuera exclusivo del usuario y no se pudiera adivinar, 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 echa un vistazo al método handle_remember_cookie!
en el archivo authenticated_system.rb
, debería poder cambiar este método para que funcione.
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 métodos restablecen el token. forget_me
lo establece en nil
, mientras que los otros dos lo establecen en el valor devuelto por make_token
. Puede anular estos métodos en el modelo de usuario para evitar que restablezcan el token si existe y no ha caducado. Ese es probablemente el mejor enfoque, o podría agregar algo de lógica adicional al método handle_remember_cookie!
, aunque eso probablemente sería más trabajo.
Si yo fuera usted, anularía remember_me_until
, forget_me
y refresh_token
en el modelo de usuario. Lo 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, está eliminando las funciones que lo protegen del robo de testigos. Pero esa es una decisión de costo-beneficio que puede tomar.
¡Muchas gracias! Entonces, ¿cómo funciona la funcionalidad de un usuario marcando "Recordarme" ahora? ¿Todavía los recuerda por el tiempo establecido en el método 'remember_me'? – Shpigford
Todavía los recuerda durante 2 semanas, como en el método remember_me, pero esas 2 semanas comienzan la primera vez que se usa el token. En otras palabras, si inicia sesión desde la computadora A, luego 10 días inicie sesión desde la computadora B, 4 días después, la ficha caduca en ambas computadoras. – jcnnghm
Genial. ¡De nuevo, gracias por tu ayuda! – Shpigford