【问题标题】:Getting the current request in rails from a file in lib/从 lib/ 中的文件获取 rails 中的当前请求
【发布时间】:2009-06-16 15:21:15
【问题描述】:

我已将所有用户身份验证代码放在一个位置,即 lib/auth.rb。它看起来像这样:

lib/auth.rb

module Admin

  def do_i_have_permission_to?(permission)
    # Code to check all of this goes here
  end

end

我将此模块作为应用程序助手的一部分包含在内,因此这些功能在所有视图中都可用:

application_helper.rb

require 'auth'
module ApplicationHelper
  include Admin
  # other stuff here
end

我还将它作为应用程序控制器的一部分包含在内,因此控制器同样可以调用函数:

application.rb

require 'auth'
class ApplicationController < ActionController::Base
  include Admin
end

到目前为止,一切都很好。

问题是我的应用程序不像普通的网络应用程序。具体来说,多个用户可以同时从同一台计算机登录系统(使用相同的浏览器)。我通过查看从该 IP 登录的所有人员来对操作进行身份验证,如果他们都能做到,则通过。

这意味着,如果管理员想要做某事,该管理员必须先将其他所有人注销,这很烦人。但是我们希望管理员所做的一切都得到管理员的批准。所以给我的建议是让管理员可以在他们通常无法访问的任何页面上提供用户名/密码组合(例如,“编辑用户”页面将具有这些额外的输入字段)并且身份验证例程将检查那个。这意味着

Admin::do_i_have_permission_to?(permission)

需要获取当前请求参数。我不能像在控制器中那样只使用 params[:foo],因为 params 没有定义;同样 request.parameters[:foo] 也不起作用。我的搜索显示:

  • 当前搜索参数在当前请求中,
  • 当前请求在当前控制器中,
  • 当前控制器在当前调度器中,并且
  • 我不确定当前调度程序是否保存在任何地方。

也就是说,经验告诉我,当我跳过这么多圈时,我很可能做错了。那么正确的方法是什么?我考虑过的选项是:

  • 只需将当前在 auth.rb 中的所有函数移动到 ApplicationHelper 中(我认为)他们就可以访问请求等。有效,但把助手搞得一团糟。
  • 将所有函数移到其他地方,他们会看到这些方法(我不知道在哪里)
  • 我只是缺少一些东西。

【问题讨论】:

    标签: ruby-on-rails ruby request


    【解决方案1】:

    在典型的 Rails 应用程序中,身份验证信息存储在活动会话中,而不是参数中。因此,编写一个可以执行您想要的操作的助手非常简单。

    创建一个然后包含在 ApplicationHelper 中的模块似乎相当不正统。传统的方法是创建一个单独的帮助程序,在这种情况下可能称为 AuthenticationHelper。然后可以将其包含在任何所需的控制器中,或者如果您愿意,可以将其加载到 ApplicationController 中以使其普遍可用。

    一般而言,Helper 不应包含其他 Helper。最好将多个帮助程序简单地加载到给定的控制器中。

    Helper 方法可以完全访问在它们操作的控制器上下文中声明的任何实例变量。具体来说,这些只是实例变量(@name),而不是局部变量(name)。辅助方法也会针对特定视图执行。

    此外,我不确定为什么用户会在同一步骤中提供凭据并执行操作,至少对于传统的基于 Web 的应用程序而言。通常流程是登录,然后单独执行一个动作。

    但是,对于每个事务都是独立操作的API,最直接的做法是拉出处理身份验证的相关请求参数,建立一些控制器实例变量,然后继续执行给定凭据所施加的限制的特定请求。

    对于这类事情,我通常采用的方法是在 ApplicationController 本身中添加一个身份验证结构,它可以执行所需的检查。这些是受保护的方法。

    虽然很想将它们卷入一大堆,例如 can_edit_user?和can_create_group?这些很快就会失控。为通用的 can_perform 挂上钩子是一种更简单的设计吗?或 has_authority_to?传递操作和任何必需参数的方法。

    例如,一个非常粗略的实现:

      class ApplicationController < ActionController::Base
      protected
        def has_authority_to?(operation, conditions = { })
          AuthenticationCheck.send(operation, conditions)
        rescue
          false
        end
      end
    
      module AuthenticationCheck
        def self.edit_user?(conditions)
          session_user == conditions[:user]
        end
      end
    
      class UserController
        # ...
    
        def edit
          @user = User.find(params[:id])
    
          unless (has_authority_to?(:edit_user, :user => @user))
            render(:partial => 'common/access_denied', :status => :forbidden)
          end
        rescue ActiveRecord::RecordNotFound
          render(:partial => 'users/not_found')
        end
      end
    

    显然,您希望将大量权限检查滚动到 before_filter 块中,以避免重复并提高一致性。

    一个完整的框架示例可能会更有帮助,例如腕带用户身份验证系统:

    http://github.com/theworkinggroup/wristband/tree/master

    【讨论】:

    • 我将功能分离到一个模块中,因为我希望它可以从视图或控制器中调用(我编辑了上面的内容以使这一点更清楚)我按照建议做了并创建了一个 authentication_helper.rb 文件具有前面提到的所有功能,但它们似乎在其他任何地方都不可见。 (尽管在我的控制器中放置了“helper:authentication”,但我得到了“NoMethodError”)对于它的价值,我想要这些功能的原因是我可以像你上面概述的那样使用它们,我只是希望它们在任何地方都可用:控制器、视图、测试等
    • 啊,我所有的 authentication_helper.rb 函数都在它们自己的模块中 (AuthenticationHelper) - 在适当的地方放置“包含 AuthenticationHelper”让它在任何地方都可以工作,谢谢!
    • 如果您想要同时也是控制器方法的辅助方法,那么您真正需要的是一组带有 helper_method 调用标记的受保护 ApplicationController 方法。例如:def is_user_admin? false end helper_method :is_user_admin?
    猜你喜欢
    • 2019-11-13
    • 2012-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    相关资源
    最近更新 更多