在 Rails 应用程序中实现“记住我”
Posted
技术标签:
【中文标题】在 Rails 应用程序中实现“记住我”【英文标题】:Implementation of "Remember me" in a Rails application 【发布时间】:2010-09-05 06:04:02 【问题描述】:我的 Rails 应用有一个带有“记住我”复选框的登录框。选中该框的用户即使在关闭浏览器后仍应保持登录状态。我通过将用户的 id 存储在用户的会话中来跟踪用户是否登录。
但是会话在 Rails 中实现为会话 cookie,它不是持久的。我可以让它们持久化:
class ApplicationController < ActionController::Base
before_filter :update_session_expiration_date
private
def update_session_expiration_date
options = ActionController::Base.session_options
unless options[:session_expires]
options[:session_expires] = 1.year.from_now
end
end
end
但这似乎是一种 hack,对于如此常见的功能来说,这令人惊讶。有没有更好的办法?
编辑
Gareth 的回答非常好,但我仍然希望熟悉 Rails 2 的人回答(因为它是独一无二的 CookieSessionStore
)。
【问题讨论】:
【参考方案1】:您几乎可以肯定不应该将会话 cookie 延长为长期存在。
尽管this article 没有专门处理rails,但还是会花一些时间解释“记住我”的最佳实践。
虽然你应该总结一下:
向用户表添加一个额外的列以接受较大的随机值 在客户端设置一个长寿命的cookie,它结合了用户ID和随机值 当新会话开始时,检查 id/value cookie 是否存在,如果匹配,则对新用户进行身份验证。作者还建议在每次登录时使随机值无效并重置 cookie。就我个人而言,我不喜欢这样,因为你不能在两台计算机上保持登录到一个站点。我倾向于确保我的密码更改功能也重置随机值,从而锁定其他机器上的会话。
最后一点,他提出的关于使某些功能(密码更改/电子邮件更改等)对自动认证会话不可用的建议非常值得遵循,但在现实世界中很少见。
【讨论】:
查看jaspan.com/improved_persistent_login_cookie_best_practice 建议文章的改进,它添加了“系列”概念以提高安全性。另外您的描述也不准确:1)您文章的作者建议在用户和cookie之间建立一个一对多的映射表,以避免在切换计算机(即工作和家庭)时不断使您的登录无效2)无效的随机cookie不会导致你描述的(两台电脑问题) 这个答案具有误导性。持久会话是安全的,因为 Rails 提供的签名 cookie 是安全的。使用此答案中建议的方法只有一个原因,即“最后一点”:此方法可用于区分手动和自动(通过“记住我”cookie)身份验证。 我想出了一个基于这个的解决方案。我没有依赖新列,而是使用Digest::SHA512.base64digest(user.password_digest)
作为我的令牌。 password_digest
已经是一个受保护的值,但 SHA512 会更加保护它。然后我将 user_id 存储在服务器端的会话中,这样我每次会话只需计算一次 SHA512。更改密码时,此功能将失效。【参考方案2】:
restful_authentication 插件有一个很好的实现:
http://agilewebdevelopment.com/plugins/restful_authentication
【讨论】:
【参考方案3】:请注意,您不想保留他们的会话,只保留他们的身份。当他们返回您的站点时,您将为他们创建一个新会话。通常,您只需为用户分配一个 GUID,将其写入他们的 cookie,然后在他们回来时使用它来查找他们。不要使用他们的登录名或用户 ID 作为令牌,因为它很容易被猜到并允许狡猾的访问者劫持其他用户的帐户。
【讨论】:
【参考方案4】:我花了一段时间思考这个问题并得出了一些结论。默认情况下,Rails 会话 cookie 是防篡改的,因此您真的不必担心 cookie 在客户端被修改。
这是我所做的:
会话 cookie 设置为长寿命(6 个月左右) 在会话存储中 设置为登录 + 24 小时的“过期”日期 用户名 Authenticated = true 所以我可以允许匿名用户会话(由于 cookie 防篡改保护不危险) 我在应用程序控制器中添加了一个 before_filter,用于检查会话的“过期时间”部分。当用户选中“记住我”框时,我只是将 session[:expireson] 日期设置为登录 + 2 周。没有人可以窃取 cookie 并永远保持登录状态或伪装成另一个用户,因为 rails session cookie 是防篡改的。
【讨论】:
默认情况下,Rails 会话 cookie 只是浏览器会话,因此当浏览器关闭时 cookie 会被删除。您如何在解决方案中执行第一步,您使用的是什么版本的 Rails? “会话 cookie 设置为长寿命(6 个月左右)” 我更改了默认设置,使会话 cookie 不是“仅浏览器会话”。这个答案是 4 年前形成的,配置/默认值可能不适用于较新版本的 Rails。【参考方案5】:我建议您查看具有此实现的 RESTful_Authentication 插件,或者只是切换您的实现以使用 RESTful Authentication_plugin。在 Railscasts 上有一个关于如何使用这个插件的很好的解释:
railscasts #67 restful_authentication
这是插件本身的链接
restful_authentication
【讨论】:
【参考方案6】:这对我来说就像一个魅力:
http://squarewheel.wordpress.com/2007/11/03/session-cookie-expiration-time-in-rails/
现在我的 CookieStore 会话将在两周后到期,因此用户必须再次提交其登录凭据才能持续登录两周。
基本上,它很简单:
-
在 vendor/plugins 目录中包含一个文件
仅使用一行在应用程序控制器中设置会话到期值
【讨论】:
【参考方案7】:我会选择 Devise 以获得出色的 Rails 身份验证解决方案。
【讨论】:
以上是关于在 Rails 应用程序中实现“记住我”的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Rails 应用程序中实现 Paypal Rest API