Ruby on Rails设计不活动后的Timeoutable重定向

时间:2016-04-01 14:31:52

标签: ruby-on-rails devise session-timeout

我正在使用Devise的Timeoutable功能,我有点困惑。如果用户的会话超时,则当他们刷新页面或执行涉及Rails控制器的操作(例如,导航到站点内的另一页面)时,会将其重定向到登录页面。但是,由于我网站上的用户敏感信息,我想在超时发生后立即自动将用户发送到登录屏幕。有没有一种标准的方法呢?

以下是我的参考代码:https://stackoverflow.com/a/35464748/4714425

2 个答案:

答案 0 :(得分:11)

我最终在@Sergio Tulentsev的帮助下找到了我自己的问题的答案,他在Stack Overflow答案的评论中给了我一些有用的信息:https://stackoverflow.com/a/14577951/4714425

基本上,Devise的Timeoutable功能默认情况下每隔30分钟就会使身份验证令牌过期...或者您可以在 config / intializers / devise.rb 中将其配置为您想要的任何时间:< / p>

# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
# time the user will be asked for credentials again. Default is 30 minutes.
config.timeout_in = 30.minutes

问题

因为Devise在服务器端而不是客户端运行,所以当身份验证令牌超时时,客户端在用户执行调用Rails控制器的操作之前不会知道超时。这意味着在执行调用Rails控制器的操作之前,用户不会在超时时重定向到登录页面。

在我的情况下,这是一个问题,因为我的网页包含用户敏感信息,如果用户忘记注销,我不想无限期地显示这些信息。

解决方案

我安装了gem auto-session-timeout,它将代码添加到客户端,以定期检查身份验证令牌是否已过期。

依赖关系

它在自述文件中没有说,但自动会话超时需要jquery-periodicalupdater才能工作。 This page包含以下原因: auto-session-timeout periodicalupdater explanation

配置

以下是为了让自动会话超时与Devise一起使用而采取的步骤:

  1. 首先,我按照步骤here来自定义Devise会话控制器。仅供参考,我的 config / routes.rb 文件按以下方式设置:

    Myapp::Application.routes.draw do
      devise_for :users, controllers: { sessions: "users/sessions" }
      #other routes
    end
    
  2. app / controllers / users / sessions_controller.rb 中,我有以下代码:

    class Users::SessionsController < Devise::SessionsController
      layout 'login' #specifies that the template app/views/layouts/login.html.erb should be used instead of app/views/layouts/application.html.erb for the login page
    
      #configure auto_session_timeout
      def active
        render_session_status
      end
    
      def timeout
        flash[:notice] = "Your session has timed out."
        redirect_to "/users/sign_in"
      end
    end
    
  3. app / controllers / application_controller.rb 中,我有以下代码:

    class ApplicationController < ActionController::Base
      # Prevent CSRF attacks by raising an exception.
      # For APIs, you may want to use :null_session instead.
      protect_from_forgery with: :exception
      before_action :authenticate_user!
      auto_session_timeout 30.minutes
    
    end
    

    请注意,我们使用auto_session_timeout将身份验证令牌到期时间设置为30分钟。这取代了Devise超时功能。

  4. 在我的应用中,我有两个布局模板 - 一个用于用户登录时看到的所有页面( app / views / layouts / application.html.erb ),一个仅用于登录屏幕( app / views / layouts / login.html.erb )。在这两个文件中,我在html <body>元素中添加了以下行:

    <%= auto_session_timeout_js %>
    

    此代码将生成Javascript,每隔60秒检查一次身份验证令牌的状态(此时间间隔是可配置的)。如果令牌已超时,则Javascript代码将调用 app / controllers / users / sessions_controller.rb 文件中的timeout方法。

    请注意,我已将此代码包含在 app / views / layouts / login.html.erb 页面中。这是因为如果登录页面上没有活动超过30分钟(或 application_controller.rb 文件中的auto_session_timeout设置),则认证令牌将过期,用户在尝试登录时将收到无效的身份验证令牌错误。添加代码<%= auto_session_timeout_js %>将导致在身份验证令牌过期时刷新登录,从而防止发生此错误。

答案 1 :(得分:0)

我宁愿避免使用不必要的宝石

  • 在您的设计模型中启用timeoutable(在我的情况下为app/model/user.rb
  • 创建config/initializer/custom_failure_app.rb
class CustomFailureApp < Devise::FailureApp 
  def redirect_url 
    if request.xhr? 
      send(:"new_#{scope}_session_path", :format => :js)
    else
      super
    end
  end
end
  • 编辑config/initializer/devise.rb
config.timeout_in = 30.minutes
config.http_authenticatable = false
config.http_authenticatable_on_xhr = false
config.navigational_formats = ["*/*", :html, :js]

config.warden do |manager|
  manager.failure_app = CustomFailureApp
end
  • 创建view/devise/sessions/new.js.erb
 window.location = "/"

通常这就足够了,但是设计new的{​​{1}}操作使用的是sessions_controller,它无法管理respond_with。 因此,我们创建了一个具有多种格式的新控制器,并覆盖了会话:js

  • 创建new
app/controllers/sessions_controller.erb
  • 编辑class SessionsController < Devise::SessionsController def new self.resource = resource_class.new(sign_in_params) clean_up_passwords(resource) yield resource if block_given? respond_to do |format| format.js format.html end end end [根据您的配置评估path_prefix的使用情况]
config/routes.rb