Kev*_*ica 19 ruby-on-rails devise
我正在和Devise一起开发RoR应用程序.我想让客户端向服务器发送请求,以查看在客户端上的用户由于不活动而自动注销之前剩余的时间(使用Timeoutable模块).我不希望此请求导致Devise重置倒计时,直到用户注销.我该如何配置?
这是我现在的代码:
class SessionTimeoutController < ApplicationController
before_filter :authenticate_user!
# Calculates the number of seconds until the user is
# automatically logged out due to inactivity. Unlike most
# requests, it should not reset the timeout countdown itself.
def check_time_until_logout
@time_left = current_user.timeout_in
end
# Determines whether the user has been logged out due to
# inactivity or not. Unlike most requests, it should not reset the
# timeout countdown itself.
def has_user_timed_out
@has_timed_out = current_user.timedout? (Time.now)
end
# Resets the clock used to determine whether to log the user out
# due to inactivity.
def reset_user_clock
# Receiving an arbitrary request from a client automatically
# resets the Devise Timeoutable timer.
head :ok
end
end
Run Code Online (Sandbox Code Playgroud)
SessionTimeoutController#reset_user_clock因为RoR每次收到来自经过身份验证的用户的请求,Timeoutable#timeout_in都会重置为我已配置的任何内容 Devise#timeout_in.如何防止在复位check_time_until_logout和has_user_timed_out?
Kev*_*ica 24
我最终不得不对我的代码进行一些更改.我会在完成后展示我最终得到的东西,然后解释它的作用:
class SessionTimeoutController < ApplicationController
# These are what prevent check_time_until_logout and
# reset_user_clock from resetting users' Timeoutable
# Devise "timers"
prepend_before_action :skip_timeout, only: [:check_time_until_logout, :has_user_timed_out]
def skip_timeout
request.env["devise.skip_trackable"] = true
end
skip_before_filter :authenticate_user!, only: [:has_user_timed_out]
def check_time_until_logout
@time_left = Devise.timeout_in - (Time.now - user_session["last_request_at"]).round
end
def has_user_timed_out
@has_timed_out = (!current_user) or (current_user.timedout? (user_session["last_request_at"]))
end
def reset_user_clock
# Receiving an arbitrary request from a client automatically
# resets the Devise Timeoutable timer.
head :ok
end
end
Run Code Online (Sandbox Code Playgroud)
这些是我所做的改变:
运用 env["devise.skip_trackable"]
这是阻止Devise重置由于不活动而将用户注销之前等待的时间的代码:
prepend_before_action :skip_timeout, only: [:check_time_until_logout, :has_user_timed_out]
def skip_timeout
request.env["devise.skip_trackable"] = true
end
Run Code Online (Sandbox Code Playgroud)
此代码更改Devise在内部使用的哈希值,以决定是否更新其存储的值以跟踪用户上次有活动的时间.具体来说,这是我们正在与之交互的设计代码(链接):
Warden::Manager.after_set_user do |record, warden, options|
scope = options[:scope]
env = warden.request.env
if record && record.respond_to?(:timedout?) && warden.authenticated?(scope) && options[:store] != false
last_request_at = warden.session(scope)['last_request_at']
if record.timedout?(last_request_at) && !env['devise.skip_timeout']
warden.logout(scope)
if record.respond_to?(:expire_auth_token_on_timeout) && record.expire_auth_token_on_timeout
record.reset_authentication_token!
end
throw :warden, :scope => scope, :message => :timeout
end
unless env['devise.skip_trackable']
warden.session(scope)['last_request_at'] = Time.now.utc
end
end
end
Run Code Online (Sandbox Code Playgroud)
(请注意,每次Rails处理来自客户端的请求时都会执行此代码.)
接近尾声的这些线对我们来说很有趣:
unless env['devise.skip_trackable']
warden.session(scope)['last_request_at'] = Time.now.utc
end
Run Code Online (Sandbox Code Playgroud)
这是"重置"倒计时的代码,直到用户因不活动而退出.它只env['devise.skip_trackable']在不执行时执行true,因此我们需要在Devise处理用户请求之前更改该值.
为此,我们告诉Rails env['devise.skip_trackable']在它做任何其他事情之前改变它的值.再次,从我的最终代码:
prepend_before_action :skip_timeout, only: [:check_time_until_logout, :has_user_timed_out]
def skip_timeout
request.env["devise.skip_trackable"] = true
end
Run Code Online (Sandbox Code Playgroud)
高于这一点的一切都是我需要改变来回答我的问题.我需要做一些其他的改变才能让我的代码按照我的意愿工作,所以我也会在这里记录它们.
Timeoutable正确使用
我误读了关于Timeoutable模块的文档,所以我的问题中的代码还有其他几个问题.
首先,我的check_time_until_logout方法总是返回相同的值.这是我所采取行动的错误版本:
def check_time_until_logout
@time_left = current_user.timeout_in
end
Run Code Online (Sandbox Code Playgroud)
我认为这Timeoutable#timeout_in将返回用户自动注销之前的时间量.相反,它返回Devise配置为在用户注销之前等待的时间量.我们需要计算用户离开的时间.
为了计算这一点,我们需要知道用户上次具有Devise识别的活动的时间.这段代码来自我们上面看到的Devise源代码,用于确定用户上次活动的时间:
last_request_at = warden.session(scope)['last_request_at']
Run Code Online (Sandbox Code Playgroud)
我们需要获取返回的对象的句柄warden.session(scope).它看起来像user_session乱码,它设计为我们提供了类似的手柄current_user和user_signed_in?,是该对象.
使用user_session哈希并计算自己剩余的时间,该check_time_until_logout方法变为
def check_time_until_logout
@time_left = Devise.timeout_in - (Time.now - user_session["last_request_at"]).round
end
Run Code Online (Sandbox Code Playgroud)
我也误读了文档Timeoutable#timedout?.当您传入用户上次活动的时间时,它会检查用户是否已超时,而不是在您传入当前时间时.我们需要做的改变很简单:Time.now我们需要在user_session哈希中传入时间而不是传入:
def has_user_timed_out
@has_timed_out = (!current_user) or (current_user.timedout? (user_session["last_request_at"]))
end
Run Code Online (Sandbox Code Playgroud)
一旦我做了这三个更改,我的控制器就按照我的预期方式行事.
pho*_*oet 17
当我正确地看到这个(可能取决于设计版本)时,设计通过Timeoutable模块处理注销.
这连接到warden,它是机架中间件堆栈的一部分.
如果你看代码,你可以找到这个部分:
unless warden.request.env['devise.skip_trackable']
warden.session(scope)['last_request_at'] = Time.now.utc
end
Run Code Online (Sandbox Code Playgroud)
所以从我在这里可以看到的,你应该能够devise.skip_trackable在看到warden中间件之前设置为true.
我认为这个问题在这里解释了如何实际使用它:https://github.com/plataformatec/devise/issues/953
| 归档时间: |
|
| 查看次数: |
4105 次 |
| 最近记录: |