【问题标题】:Ruby on Rails Devise Timeoutable redirect after inactivityRuby on Rails 在不活动后设计超时重定向
【发布时间】:2016-04-01 14:31:52
【问题描述】:

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

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

【问题讨论】:

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


    【解决方案1】:

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

    基本上,Devise 的 Timeoutable 功能默认会每 30 分钟过期一次身份验证令牌...或者您可以在 config/initializers/devise.rb 中将其配置为您想要的任何时间:

    # ==> 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 包含原因:

    配置

    为了让自动会话超时与 Devise 一起工作,我采取了以下步骤:

    1. 首先,我按照here 的步骤来自定义设计会话控制器。仅供参考,我的 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 分钟。这取代了设计超时功能。

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

      <%= 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 设置),则身份验证令牌将过期,并且用户在尝试登录时将收到 Invalid Authentication Token 错误。添加代码&lt;%= auto_session_timeout_js %&gt;会导致认证令牌过期时刷新登录,从而防止出现此错误。

    【讨论】:

    • 您好,非常感谢!我有一个问题 - 你说它取代了设计超时功能,但这仅在 JS 上,所以用户可以绕过它。我们不应该在客户端和服务器上都有它吗?
    • @dowi 这是一个非常好的观点。我没有想到这一点。那么,除了 Devise 的超时功能之外,使用 auto_session_timeout 可能不是一个坏主意。看了这段代码已经有一段时间了,但如果我没记错的话,两者之间没有任何不兼容的问题。我想我只是建议删除 Devise 促进更简洁代码的超时功能。
    • 好的,谢谢!我有设计功能,我会添加您的建议以获得更好的用户体验
    【解决方案2】:

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

    • 在您的设计模型中启用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 = "/"
    

    通常这已经足够了,但设计sessions_controller 中的new 操作使用无法管理:jsrespond_with。 所以我们创建一个具有多种格式的新控制器并覆盖会话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
    
    • 编辑config/routes.rb [根据您的配置评估 path_prefix 的使用]
    devise_for :users, :path_prefix => 'd', controllers: { sessions: 'sessions' }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-16
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      • 2015-10-28
      • 2016-06-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多