我们的Rails应用程序正在使用Restful Authentication进行用户/会话管理,似乎从多台计算机登录到同一帐户会导致其他计算机上的会话被杀死,从而导致“记住我”功能被杀死。
所以说我在家里并登录应用程序(并检查“记住我”)。然后我去办公室登录(并检查“记住我”)。然后,当我回到家时,我返回应用程序,并且必须重新登录。
如何允许从多台计算机登录并保持“记住我”功能的所有功能?
答案 0 :(得分:9)
这样做会牺牲一些安全性,但这绝对是可能的。有两种方法可以实现这一目标。
在第一个中,您可以覆盖用户模型中的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
这样可以确保令牌永远不会改变,但也可以让任何获得令牌的人冒充用户。
除此之外,如果您查看authenticated_system.rb
文件中的handle_remember_cookie!
方法,您应该可以更改此方法以便为您效用。
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
请注意,通过执行此操作,您将获取保护您免受令牌窃取的功能。但这是您可以做出的成本效益决定。
答案 1 :(得分:0)
您可以更改remember_token
实现此目的的内容。您可以将其设置为:
self.remember_token = encrypt("#{email}--extrajunkcharsforencryption")
而不是
self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
现在没有任何计算机或时间特定的令牌,您可以保持从多台计算机登录。