【问题标题】:Where to override current_user helper method of devise gem在哪里覆盖设计 gem 的 current_user 辅助方法
【发布时间】:2012-04-27 11:14:16
【问题描述】:

如何覆盖 devise gem 的 current_user 实际上我需要为移动应用添加网络服务。

目前的设计是管理网络应用程序的会话和“当前用户”。

现在移动应用程序会将 user_id 发送到服务器。我需要像这样覆盖当前用户

def current_user
  if params[:user_id].blank?
    current_user
  else
    User.find(params[:user_id])
  end   
end

我是否需要将 devise gem 修改为插件?还是别的什么?
请详细解释,因为我是 Rails 新手。

亲切的问候,

【问题讨论】:

  • 哎呀...所以,您是说当移动代理发送 user_id 时您会信任它?
  • 还有一些认证秘钥
  • Devise 将处理 token_authenticable - 只需向上传递 authentication_token,不需要 user_id。

标签: ruby-on-rails-3 authentication ruby-on-rails-3.1 rubygems devise


【解决方案1】:

根据模块Devise::Controllers::Helperscurrent_user(连同所有其他设计助手)被添加到ApplicationController,这意味着您可以通过这种方式覆盖它:

# in application_controller.rb

def devise_current_user
  @devise_current_user ||= warden.authenticate(scope: :user)
end

def current_user
  if params[:user_id].blank?
    devise_current_user
  else
    User.find(params[:user_id])
  end   
end

【讨论】:

  • 启动我的环境时,“alias_method”行出现错误:类 ApplicationController (NameError) 的 undefined_method 'current_user'。如果我将其注释掉,启动并取消注释,它就可以正常工作。有解决办法吗?
  • Frexuz,尝试将 alias_method 替换为:def devise_current_user { @devise_current_user ||=warden.authenticate(:scope => :user) }
  • 这是线程安全的吗?在 MRI 上进行身份验证后,控制器的奇怪点出现零错误。
  • 为什么别名 current_user 而不是调用 super?
  • alias_method 比调用super 更好,以防您实际上需要访问原始current_user。您可能在某些时候需要它(例如if current_user != devise_current_user #etc.)。
【解决方案2】:

建议对方法进行别名的其他答案实际上不是最佳解决方案。 Doug English 的评论是最好的解决方案:

# In ApplicationHelper
def devise_current_user
   @devise_current_user ||= warden.authenticate(:scope => :user)
end

原因如下:

假设您将 ApplicationHelper 包含在控制器中。如果您的 ApplicationHelper 中需要一个依赖于 devise_current_user 的方法,鉴于控制器内部的别名解决方案,那么您就不走运了。

但是使用上面的显式方法定义,您可以将定义移动到帮助程序并从其他方法调用它,您仍然可以将其包含在控制器中。

这很有用,例如,当您开发用户模拟解决方案并且需要在视图中显示两个不同的用户时,一个用于真正的管理员 (devise_current_user),另一个用于模拟用户 (current_user)。

【讨论】:

  • 确实你是对的。请注意,ApplicationController 中应包含以下内容:include ApplicationHelper。否则,devise_current_user 将变为未知。
【解决方案3】:

Limbo-Peng 的回答很棒,但可以稍作改进以确保只有管理员才能做到这一点:

您还需要在 User 类上定义 is_admin? 方法或 is_admin 属性。

您可能还想使用与user_id 不同的密钥,因此它永远不会与您的常规参数冲突。

# to impersonate another user, e.g. for customer support
# only admins can do this..
#
alias_method :devise_current_user, :current_user
def current_user
  if ! params[:user_id].blank? \
     && devise_current_user && devise_current_user.is_admin? 
    User.find(params[:user_id])
  else
    devise_current_user
  end
end

【讨论】:

    【解决方案4】:

    假设我们可以信任我们的会话数据(这取决于您是否在未经适当授权的情况下将用户输入放入其中),这可能会引起关注:

    module Concerns
      module ControllerWithImpersonation
        extend ActiveSupport::Concern
    
        included do
          helper_method :devise_current_user
        end
    
        def current_user
          if session[:impersonated_user_id].blank?
            devise_current_user
          else
            User.find(session[:impersonated_user_id])
          end
        end
    
        def devise_current_user
          @devise_current_user ||= warden.authenticate(:scope => :user)
        end
    
      end
    end
    

    我现在在一个项目中使用它。

    一个小问题(在回答中,抱歉)...我是否应该知道 Devise 或 Warden 的任何更改使上述 devise_current_user 过时?

    【讨论】:

      猜你喜欢
      • 2011-09-19
      • 1970-01-01
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 2014-10-06
      • 1970-01-01
      相关资源
      最近更新 更多