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

发布于 2024-07-23 18:33:02 字数 1461 浏览 2 评论 0原文

我已将所有用户身份验证代码放在一个位置,即 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 中(我认为)它们就可以访问请求等。 有效,但是让助手变得混乱。
  • 将所有函数移到其他地方,他们会看到这些方法(我不知道在哪里),
  • 我只是缺少一些东西。

I've put all of my user-authentication code in one place, namely lib/auth.rb. It looks like this:

lib/auth.rb

module Admin

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

end

I include this module as part of the application helper, so these functions are available in all the views:

application_helper.rb

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

And I also include it as part of the application controller, so the controllers likewise can call the functions:

application.rb

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

So far, so good.

The problem is that my application is not like a normal web app. Specifically, more than one user can be logged into the system from the same computer at the same time (using the same browser). I do authentication for actions by looking at all the people who are logged in from that IP and if they can all do it, it passes.

What this means is that, if an admin wants to do something, that admin has to log everyone else out first, which is annoying. But we want the admin seal of approval on everything the admin does. So the suggestion given to me was to have it so the admin can supply a username/password combo on any page they would not normally have access to (e.g. an 'edit user' page would have these extra input fields) and the authentication routines would check for that. This means

Admin::do_i_have_permission_to?(permission)

needs to get at the current request parameters. I can't just use params[:foo] like I would in a controller, because params isn't defined; similarly request.parameters[:foo] will also not work. My searching has revealed:

  • The current search parameters are in the current request,
  • The current request is in the current controller,
  • The current controller is in the current dispatcher, and
  • I'm not sure the current dispatcher is kept anywhere.

That said, experience tells me that when I'm jumping through this many hoops, I'm very probably Doing It Wrong. So what is the right way to do it? Options I've considered are:

  • Just move all the functions currently in auth.rb into the ApplicationHelper where (I think) they'll have access to the request and such. Works, but clutters the hell out of the helper.
  • Move all the functions somewhere else they'll see those methods (I don't know where)
  • I'm just plain missing something.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

○闲身 2024-07-30 18:33:03

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

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

一般来说,Helpers 不应该包含其他Helpers。 最好简单地将多个助手加载到给定的控制器中。

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

此外,我不确定为什么用户会在同一步骤中提供凭据并执行操作,至少对于传统的基于网络的应用程序来说是这样。 通常该过程是登录然后单独执行操作。

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

对于此类事情,我通常遵循的方法是在 ApplicationController 本身中分层分层身份验证结构,该结构可以执行所需的检查。 这些是受保护的方法。

虽然很想卷入一大堆,例如 can_edit_user? 和can_create_group? 这些很快就会失控。 为通用 can_perform 添加一个钩子是一个更简单的设计? 或有权限? 传递操作和任何所需参数的方法。

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

  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

In a typical Rails application, authentication information is stored in the active session, not the parameters. As such, it's pretty straightforward to write a helper that does what you want.

It seems rather unorthodox to create a module that is then included in ApplicationHelper. The traditional approach is to create a separate helper which in this case would probably be called AuthenticationHelper. This can then be included in any required controllers, or if you prefer, loaded into ApplicationController to make it available universally.

In general terms, Helpers should not include other Helpers. It is better to simply load multiple helpers into a given Controller.

Helper methods have full access to any instance variables declared within the controller context they are operating from. To be specific, these are instance variables only (@name) and not local variables (name). Helper methods are executed for a particular view as well.

Further, I'm not sure why a user would be providing credentials and performing an operation in the same step, at least for traditional web-based apps. Usually the process is to log in and then perform an action separately.

However, in the case of an API where each transaction is an independent operation, the most straightforward approach is to do is pull out the relevant request parameters that deal with authentication, establish some controller instance variables, and then proceed to perform the particular request given the constraints that the credentials impose.

The approach I usually follow for this sort of thing is to layer in an authentication structure in the ApplicationController itself which can perform the required checks. These are protected methods.

While it's tempting to roll in a whole heap of them such as can_edit_user? and can_create_group? these very quickly get out of hand. It is a simpler design to put in a hook for a general-purpose can_perform? or has_authority_to? method that is passed an operation and any required parameters.

For example, a very rough implementation:

  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

Obviously you'd want to roll a lot of the authority checks into before_filter blocks to avoid repetition and to promote consistency.

A full framework example might be of more help, such as the Wristband user authentication system:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文