ruby-on-rails – Devise – 发出请求而不重置倒计时,直到用户由于不活动而退出

前端之家收集整理的这篇文章主要介绍了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

SessionTimeoutController#reset_user_clock的作用是因为每次RoR收到来自经过身份验证的用户的请求时,Timeoutable#timeout_in将重置为我在Devise#timeout_in中配置的任何内容.如何在check_time_until_logout和has_user_timed_out中阻止重置?

解决方法

我最终不得不对我的代码进行几个更改.当我完成后,我将会展示我所得到的结果,然后解释它的作用:
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

这些是我所做的改变:

使用env [“devise.skip_trackable”]

这是阻止Devise重新设置由于不活动而在登录用户之前等待多长时间的代码

prepend_before_action :skip_timeout,:has_user_timed_out]
  def skip_timeout
    request.env["devise.skip_trackable"] = true
  end

代码更改了Devise在内部使用的哈希值,以决定是否更新其存储的值以跟踪用户上次的活动时间.具体来说,这是我们正在与(link)交互的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

(请注意,每次Rails处理来自客户端的请求时,都会执行此代码.)

接近尾声的这些线对我们很有兴趣:

unless env['devise.skip_trackable']
      warden.session(scope)['last_request_at'] = Time.now.utc
    end

这是“重置”倒计时的代码,直到用户由于不活动而退出.只有在env [‘devise.skip_trackable’]不正确的情况下才执行,所以我们需要在Devise处理用户请求之前更改该值.

为了做到这一点,我们告诉Rails在做任何事情之前更改env [‘devise.skip_trackable’]的值.再次,从我的最终代码

prepend_before_action :skip_timeout,:has_user_timed_out]
  def skip_timeout
    request.env["devise.skip_trackable"] = true
  end

这一点以上的一切都是我需要改变来回答我的问题.还有一些其他的变化,我需要让我的代码工作,因为我想要的,所以我会在这里记录他们.

正确使用超时

我错读了关于Timeoutable模块的文档,所以我的问题中的代码有一些其他问题.

首先,我的check_time_until_logout方法总是返回相同的值.这是我的动作的错误版本:

def check_time_until_logout
  @time_left = current_user.timeout_in
end

我认为Timeoutable#timeout_in将返回用户自动注销的时间.相反,它返回在记录用户之前配置Devise所需等待的时间.我们需要计算用户离开我们自己的时间.

为了计算这个,我们需要知道用户最后一次有Devise识别的活动.来自我们上面看到的Devise源代码的这段代码决定了用户最后一次活动的时间:

last_request_at = warden.session(scope)['last_request_at']

我们需要获取由warden.session(scope)返回的对象的句柄.它看起来像user_session哈希,Devise为我们提供了像handle_handler和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

我也误读了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

一旦我做了这三个变化,我的控制器按照我的预期方式行事.

猜你在找的Ruby相关文章