我已将所有用户身份验证代码放在一个地方,即 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
我将此模块作为应用程序助手的一部分包含在内,因此这些功能在所有 View 中都可用:
application_helper.rb
require 'auth'
module ApplicationHelper
include Admin
# other stuff here
end
我还将它作为应用程序 Controller 的一部分包含在内,因此 Controller 同样可以调用以下函数:
application.rb
require 'auth'
class ApplicationController < ActionController::Base
include Admin
end
到目前为止,还不错。
问题是我的应用程序不像普通的网络应用程序。具体来说,可以有多个用户同时从同一台计算机登录系统(使用同一浏览器)。我通过查看所有从该 IP 登录的人来对操作进行身份验证,如果他们都能做到,则通过。
这意味着,如果管理员想做某事,该管理员必须先将其他所有人注销,这很烦人。但我们希望管理员所做的一切都得到管理员的批准。所以给我的建议是让管理员可以在他们通常无法访问的任何页面上提供用户名/密码组合(例如,“编辑用户”页面将具有这些额外的输入字段)并且身份验证例程将检查一下。这意味着
Admin::do_i_have_permission_to?(permission)
需要获取当前的请求参数。我不能像在 Controller 中那样使用 params[:foo],因为没有定义 params;同样,request.parameters[:foo] 也不起作用。我的搜索显示:
- 当前搜索参数在当前请求中,
- 当前请求在当前 Controller 中,
- 当前 Controller 在当前调度器中,并且
- 我不确定当前的调度程序是否保存在任何地方。
也就是说,经验告诉我,当我跳过这么多圈时,我很可能做错了。那么正确的做法是什么?我考虑过的选项是:
- 只需将当前在 auth.rb 中的所有函数移动到 ApplicationHelper 中(我认为)它们将可以访问请求等。有效,但会把助手搞得一团糟。
- 将所有函数移到其他地方,他们会看到这些方法(我不知道在哪里)
- 我只是缺少一些东西。
最佳答案
在典型的 Rails 应用程序中,身份验证信息存储在事件 session 中,而不是参数。因此,编写一个执行您想要的操作的帮助程序非常简单。
创建一个模块然后包含在 ApplicationHelper 中似乎是相当不正统的。传统方法是创建一个单独的助手,在这种情况下可能称为 AuthenticationHelper。然后可以将其包含在任何所需的 Controller 中,或者如果您愿意,可以将其加载到 ApplicationController 中以使其普遍可用。
一般而言,Helpers 不应包括其他 Helpers。最好将多个帮助程序简单地加载到给定的 Controller 中。
Helper 方法可以完全访问在它们运行的 Controller 上下文中声明的任何实例变量。具体来说,这些只是实例变量 (@name) 而不是局部变量 (name)。辅助方法也会针对特定 View 执行。
此外,我不确定为什么用户会在同一步骤中提供凭据和执行操作,至少对于传统的基于 Web 的应用程序而言。通常流程是登录,然后单独执行一个 Action 。
但是对于一个API来说,每个事务都是一个独立的操作,最直接的做法就是把处理鉴权的相关请求参数拉出来,建立一些controller实例变量,然后再去执行给定凭据强加的约束的特定请求。
对于这类事情,我通常采用的方法是在 ApplicationController 本身的身份验证结构中分层,它可以执行所需的检查。这些是 protected 方法。
虽然很想加入一大堆,例如 can_edit_user?和 can_create_group?这些很快就会失控。为通用的 can_perform 放入一个钩子(Hook)是一种更简单的设计吗?或 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 block 中以避免重复并提高一致性。
一个完整的框架示例可能会有更多帮助,例如 Wristband 用户身份验证系统:
关于ruby-on-rails - 从 lib/中的文件获取 rails 中的当前请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1002200/