从lib /中的文件获取当前请求

时间:2009-06-16 15:21:15

标签: ruby-on-rails ruby request

我已将所有用户身份验证代码放在一个位置,即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中,我认为他们可以访问请求等等。工作,但把帮助者弄得一团糟。
  • 将所有功能移到其他地方,他们会看到那些方法(我不知道在哪里)
  • 我只是遗漏了一些东西。

1 个答案:

答案 0 :(得分:4)

在典型的Rails应用程序中,身份验证信息存储在活动会话中,而不是参数中。因此,编写一个能够完成你想要的帮助是非常简单的。

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

一般而言,助手不应包括其他助手。最好将多个helper加载到给定的Controller中。

Helper方法可以完全访问在其操作的控制器上下文中声明的任何实例变量。具体而言,这些只是实例变量(@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块中,以避免重复并提高一致性。

完整的框架示例可能会提供更多帮助,例如Wristband用户身份验证系统:

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