我一直在使用 Devise,并依靠用户模型的 last_sign_in_at 来确定我的客户是否在 X 天内没有返回。但是,我最近发现 last_sign_in_at 仅在发生实际表单登录事件时才更新,而不是在用户自动登录时更新,因为包含了可记住的。
如果要确保每次用户登录(新的浏览器会话)时更新 last_sign_in_at,无论他们是使用表单登录还是由可记住的 cookie 自动登录,我将如何在设计兼容方式?
我一直在使用 Devise,并依靠用户模型的 last_sign_in_at 来确定我的客户是否在 X 天内没有返回。但是,我最近发现 last_sign_in_at 仅在发生实际表单登录事件时才更新,而不是在用户自动登录时更新,因为包含了可记住的。
如果要确保每次用户登录(新的浏览器会话)时更新 last_sign_in_at,无论他们是使用表单登录还是由可记住的 cookie 自动登录,我将如何在设计兼容方式?
采取 Matthew 的解决方案,我认为代码应该如下(注意 session[:logged_signin] 之前的 not-operator):
before_filter :update_last_sign_in_at
protected
def update_last_sign_in_at
if user_signed_in? && !session[:logged_signin]
sign_in(current_user, :force => true)
session[:logged_signin] = true
end
end
可跟踪的钩子来自Warden 的 after_set_user钩子——您可以做的很容易解决这个问题的方法是设置一个 before_filter 来调用sign_in。
这可以优化,但测试看看是否使用
before_filter proc{ sign_in(current_user, :force => true) }
更新 last_signed_in_at 时间戳。
Devise: rememberable 表示 last_sign_in_at 不被 trackable 更新
扩展之前的解决方案,他们的问题是如果用户正常登录,他们将“登录两次”。它将设置last_sign_in_at
为与 . 相同(或几乎相同)的值current_sign_in_at
。在我的网站上,我习惯于last_sign_in_at
让用户知道自他们上次访问该网站以来发生了什么,因此我需要它有点准确。此外,它还会记录 +1 登录计数。
此外,有些人(比如我自己)将浏览器窗口打开了好几天而没有关闭它(因此从不清除会话标志)。出于度量目的等,如果此类用户行为有时会刷新current_sign_in_at
时间,这可能会很有用。
以下变体将解决这些问题。
class ApplicationController < ActionController::Base
before_filter :update_sign_in_at_periodically
UPDATE_LOGIN_PERIOD = 10.hours
protected
def update_sign_in_at_periodically
if !session[:last_login_update_at] or session[:last_login_update_at] < UPDATE_LOGIN_PERIOD.ago
session[:last_login_update_at] = Time.now
sign_in(current_user, :force => true) if user_signed_in?
end
end
end
但是,当我使用 Devise 3.2.4 尝试上述操作时,当它通过 cookie 自动登录(登录计数 +1 并current_sign_in_at
正在设置)时,我确实获得了新的登录。因此,我只剩下希望跟踪定期更新的问题,即使对于保持会话打开的用户也是如此。
class ApplicationController < ActionController::Base
before_filter :update_sign_in_at_periodically
UPDATE_LOGIN_PERIOD = 10.hours
protected
def update_sign_in_at_periodically
# use session cookie to avoid hammering the database
if !session[:last_login_update_at] or session[:last_login_update_at] < UPDATE_LOGIN_PERIOD.ago
session[:last_login_update_at] = Time.now
if user_signed_in? and current_user.current_sign_in_at < 1.minute.ago # prevents double logins
sign_in(current_user, :force => true)
end
end
end
end
application_controller
你可以设置一个before_action
检查当前用户的 current_sign_in_at 是否比 X 前更长。如果是,则使用sign_in(current_user, force: true)
它更新 current_sign_in_at。
before_action :update_last_sign_in_at
def update_last_sign_in_at
return unless user_signed_in? && current_user.current_sign_in_at < 12.hours.ago
sign_in(current_user, force: true)
end
我使用它来检测非活动用户(未登录 6 个月)并删除它们。#GDPR
AFAIK 您也可以update_tracked_fields!
在该current_user
模型上使用。