【问题标题】:Authlogic root url based on authenticated state基于认证状态的 Authlogic 根 url
【发布时间】:2011-11-25 21:24:51
【问题描述】:

我希望能够根据 Authlogic 的登录/注销状态在 routes.rb 中设置根 url。这是我需要做的一个例子:

root :to => 'users#index', :constraints => lambda { |request| # ??? }  
root :to => 'welcome#index'  
get '/' => 'users#index', :as => 'user_root'

这将使已登录的用户可以转到users#index,而注销的用户可以转到welcome#index,而无需进行重定向。我确实知道如何设置 before_filter 并相应地重定向,但我不想那样做。

我知道Devise 可以做到这一点,但我需要为 Authlogic 解决这个问题。类似的问题here没有答案。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 authlogic


    【解决方案1】:

    您可以很容易地创建自定义路由约束。任何响应matches? 的对象都可以交给:constraints 路由选项。要检查 Authlogic 身份验证,您需要从 ApplicationController 中提取 Authlogic 方法并将它们放在其他地方。无论如何,我建议对这些使用关注点。

    # app/concerns/authlogic_methods.rb
    module AuthlogicHelpers
      extend ActiveSupport::Concern
    
      module InstanceMethods
        private # All methods are private
    
        def current_user_session
          return @current_user_session if defined?(@current_user_session)
          @current_user_session = UserSession.find
        end
    
        def current_user
          return @current_user if defined?(@current_user)
          @current_user = current_user_session && current_user_session.user
        end
      end
    end
    
    # app/controllers/application_controller.rb
    class ApplicationController < ActionController::Base
      include AuthlogicHelpers
    end
    
    # config/initializers/route_constraints.rb
    module RouteConstraints
      class LoggedIn
        include AuthlogicHelpers
        def matches?(request)
          current_user
        end
      end
    end
    
    # config/routes.rb
    constraints RouteConstraints::LoggedIn.new do
      root :to => 'dashboard#show'
    end
    

    请注意,我们正在实例化一个新的 RouteConstraints::LoggedIn 对象。这是因为 Authlogic 方法 current_usercurrent_user_session 被定义为实例方法并创建实例变量——如果它们没有为每个请求分开,您将无法确定用户实际登录或另一个用户已登录在之前。

    如果 Authlogic 尝试直接访问 params,您可能会遇到问题。在这种情况下,您可能需要重写 UserSession.new 方法以接受 request 对象作为参数并调用 request.params 以获取参数。

    【讨论】:

    • 我在自己遇到同样的问题时找到了这个答案。但是,由于 Rails 或 AuthLogic 中的更改,这似乎不适用于 Rails 4。我认为 AuthLogic 现在需要一个控制器并访问 cookie 才能激活它。 AuthlogicHelpers#InstanceMethods 中的方法也应该移动到 AuthlogicHelpers 的主体中。再次可能与ActiveSupport::Concern 发生变化。
    • @Aaron 我今天不想使用 Authlogic。 Rails 中的has_secure_password 支持与普通的 UserSession 对象和会话控制器相结合是实现经过身份验证的会话所需的全部内容。
    • 谢谢@coreyward。我会调查一下。不幸的是,我正在将 Rails 3 应用程序升级到 4,并且它已经使用 Authlogic 有一段时间了,所以这将是另一组更改,我必须等到将来再考虑。
    • @Aaron 啊,可以理解。迁移现有用户的系统很困难。希望你可以让 Authlogic 在 Rails 4 下为你工作。
    • 这不是一个理想的解决方案,但我们可以急切地处理另一个根路由,方法是检查请求对象并在它碰巧无效或被欺骗时让控制器再次重定向。类似get '/', to: 'some_authed_controller#action', constraints: lambda {|req| req.env['rack.session']['some_user_key'].present? }
    【解决方案2】:

    Authlogic 已经拥有机器原生(针对 Rails 6.0 和 Authlogic 6.0 测试):

    class AuthlogicSignedInConstraint
      def matches?(request)
        Authlogic::Session::Base.controller = Authlogic::ControllerAdapters::AbstractAdapter.new(request)
        user_session = UserSession.find
        user_session && user_session.user
      end
    end
    

    【讨论】:

    • 谢谢!也适用于 Rails 5.0 / Authlogic 3.5
    【解决方案3】:

    最近版本中的 Authlogic 需要实例化控制器对象,否则它无法找到加载会话所需的会话数据。

    事实上,authlogic/controller_adapters/ 下包含各种控制器实现的适配器:Rails 控制器、Sinatra 和 Rack。

    接口相当简单,所以我编写了一个适配器来使用ActionDispatch::Request,它可以在约束内访问。

    这已经在 Rails 4.2 上测试过了,Rails 5 应该是类似的。

    class AuthlogicRequestAdapter
      attr_reader :request
    
      def initialize(request)
        @request = request
      end
    
      def authenticate_with_http_basic
      end
    
      def cookies
        request.cookies
      end
    
      def params
        request.params
      end
    
      def session
        _, session_hash = Rails.application.config.session_store.new(Rails.application, Rails.application.config.session_options).load_session(request.env)
        session_hash
      end
    end
    

    Rails 中的使用示例

    路线限制

    class UserRouteConstraint
      def matches?(request)
        Authlogic::Session::Base.controller = AuthlogicRequestAdapter.new(request)
        user = UserSession.find
    
        if user&.record.present?
          true
        else
          false
        end
      end
    end
    

    routes.rb

    MyRailsApp::Application.routes.draw do
      # ... other routes
    
      constraints(UserRouteContraint.new) do
        root :to => 'users#index'
      end
    
      root :to => 'welcome#index'  
      get '/' => 'users#index', :as => 'user_root'
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-16
      • 2019-12-05
      • 1970-01-01
      • 2019-06-17
      • 2021-10-03
      • 2011-12-25
      相关资源
      最近更新 更多