Hai intenzione di sacrificare un po 'di sicurezza in questo modo, ma è sicuramente possibile. Ci sono due modi in cui dovresti essere in grado di farlo.
Nel primo, è possibile sostituire il metodo make_token nel modello utente. Il modello è attualmente implementato come segue.
def make_token
secure_digest(Time.now, (1..10).map{ rand.to_s })
end
Ogni volta che un utente accede, con o senza un cookie, il metodo si chiama make_token
che genera e salva un nuovo remember_token
per l'utente. Se si aveva un altro valore che era unico per l'utente che non poteva essere indovinato, è possibile sostituire il metodo make_token
.
def make_token
secure_digest(self.some_secret_constant_value)
end
Ciò garantirebbe che il token non cambia mai, ma sarebbe anche permettere a nessuno che ha ottenuto il token per rappresentare l'utente.
Oltre a questo, se si dà un'occhiata al metodo handle_remember_cookie!
nel file authenticated_system.rb
, si dovrebbe essere in grado di cambiare questo metodo per lavorare per voi.
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
Si noterà che questo metodo chiama tre metodi nel modello di utente, refresh_token
, remember_me
e 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
Tutti e tre questi metodi reimpostano il token. forget_me
lo imposta su nil
, mentre gli altri due lo impostano sul valore restituito da make_token
. È possibile eseguire l'override di questi metodi nel modello utente per impedire che reimpostino il token se esiste e non è scaduto. Questo è probabilmente l'approccio migliore, oppure potresti aggiungere qualche logica aggiuntiva al metodo handle_remember_cookie!
, anche se probabilmente sarebbe più un lavoro.
Se fossi in te, sostituirò remember_me_until
, forget_me
e refresh_token
nel modello utente. Il seguente dovrebbe funzionare.
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
Nota che facendo questo, stai eliminando le funzionalità che ti proteggono dal rubare token. Ma questa è una decisione sui costi che puoi prendere.
Grazie mille! Quindi come funziona la funzionalità di un utente che controlla "Ricordami" adesso? Li ricorda ancora per la quantità di tempo impostata nel metodo 'remember_me'? – Shpigford
Si ricorda ancora di loro per 2 settimane, come nel metodo remember_me, ma che 2 settimane inizia la prima volta che viene utilizzato il token. In altre parole, se si accede dal computer A, 10 giorni dopo il login dal computer B, 4 giorni dopo il token scade su entrambi i computer. – jcnnghm
Grande. Grazie ancora per il vostro aiuto! – Shpigford