我们的Rails应用程序正在使用Restful Authentication进行用户/会话管理,似乎从多台计算机登录到同一个帐户会杀死其他计算机上的会话,从而导致“Remember me”功能失效。宁静的身份验证:允许从多台计算机登录?
所以说我在家里并登录到应用程序(并检查“记住我”)。然后我去办公室登录(并检查“记住我”)。然后,当我回到家时,我回到了应用程序,并且必须重新登录。
我该如何允许从多台机器登录并保持“记住我”的功能?
我们的Rails应用程序正在使用Restful Authentication进行用户/会话管理,似乎从多台计算机登录到同一个帐户会杀死其他计算机上的会话,从而导致“Remember me”功能失效。宁静的身份验证:允许从多台计算机登录?
所以说我在家里并登录到应用程序(并检查“记住我”)。然后我去办公室登录(并检查“记住我”)。然后,当我回到家时,我回到了应用程序,并且必须重新登录。
我该如何允许从多台机器登录并保持“记住我”的功能?
这样做会牺牲一些安全性,但这绝对有可能。有两种方法可以实现这一点。
在第一个中,您可以覆盖用户模型中的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
请注意,通过这样做,您将取消防止令牌窃取的功能。但这是您可以制定的成本收益决定。
您可以更改remember_token
所要达到的效果。你可以将其设置为:的
self.remember_token = encrypt("#{email}--extrajunkcharsforencryption")
代替
self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
现在有具体的关于令牌没有计算机或时间,你可以在多台机器保持登录。
谢谢! 那么,如何检查“记住我”的用户的功能现在工作?它是否还记得在'remember_me'方法中设置的时间量? – Shpigford 2009-12-11 03:20:52
它仍然记得它们2周,就像在remember_me方法中一样,但是在第一次使用令牌时会开始2周。换句话说,如果您从计算机A登录,则从计算机B登录10天,4天后,这两个计算机上的令牌过期。 – jcnnghm 2009-12-11 15:04:41
太好了。再次感谢你的帮助! – Shpigford 2009-12-11 18:25:11