Делая это, вы собираетесь пожертвовать некоторой безопасностью, но это определенно возможно. Это можно сделать двумя способами.
Во-первых, вы можете переопределить метод make_token в вашей пользовательской модели. Модель в настоящее время реализована следующим образом.
def make_token
secure_digest(Time.now, (1..10).map{ rand.to_s })
end
Каждый раз, когда пользователь входит в систему, с файлом cookie или без него, вызывается метод make_token
, который генерирует и сохраняет новый remember_token
для пользователя. Если у вас есть другое значение, уникальное для пользователя, которое невозможно угадать, вы можете заменить метод make_token
.
def make_token
secure_digest(self.some_secret_constant_value)
end
Это позволит гарантировать, что токен никогда не изменится, но также позволит любому, кто получил токен, выдать себя за пользователя.
Кроме этого, если вы посмотрите на метод handle_remember_cookie!
в файле authenticated_system.rb
, вы сможете изменить этот метод, чтобы он работал на вас.
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
Вы заметите, что этот метод вызывает три метода в пользовательской модели: refresh_token
, remember_me
и 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
Все три из этих методов сбрасывают токен. forget_me
устанавливает значение nil
, тогда как другие два устанавливают значение, возвращаемое make_token
. Вы можете переопределить эти методы в пользовательской модели, чтобы предотвратить сброс маркера, если он существует и срок его действия не истек. Это, вероятно, лучший подход, или вы могли бы добавить некоторую дополнительную логику в метод handle_remember_cookie!
, хотя это, вероятно, потребует больше усилий.
На вашем месте я бы переопределил remember_me_until
, forget_me
и refresh_token
в пользовательской модели. Следующее должно работать.
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
Обратите внимание, что этим вы убираете функции, защищающие вас от кражи токенов. Но это решение, которое вы можете принять с точки зрения затрат.