我一直在使用Devise,并依赖于用户模型的last_sign_in_at来计算我的客户是否在X天内没有返回。但是,我最近发现last_sign_in_at仅在实际的表单登录事件发生时更新,而不是由于包含可记住的用户而自动登录时。
如果想确保每次用户登录时更新last_sign_in_at(新的浏览器会话),无论他们是使用表单登录还是由可记忆的cookie自动登录,我将如何进行操作这与设计兼容吗?
答案 0 :(得分:15)
采用Matthew的解决方案,我认为代码应该如下(注意会话之前的not-operator [:logged_signin]):
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
答案 1 :(得分:6)
可跟踪的挂钩来自Warden's after_set_user挂钩 - 您可以轻松解决此问题,设置一个before_filter来调用sign_in。
这可以进行优化,但要测试是否使用
before_filter proc{ sign_in(current_user, :force => true) }
更新last_signed_in_at时间戳。
答案 2 :(得分:2)
Devise: rememberable means that last_sign_in_at is not updated by 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
答案 3 :(得分:0)
在application_controller
上,您可以设置一个before_action
来检查当前用户的current_sign_in_at是否比X前更长。如果是,则使用更新current_sign_in_at的sign_in(current_user, force: true)
。
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
答案 4 :(得分:-1)
AFAIK您还可以在update_tracked_fields!
型号上使用current_user
。