我已将所有用户身份验证代码放在一个位置,即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]也行不通。我的搜索显示:
那说,经验告诉我,当我跳过这么多箍时,我很可能做错了。那么正确的方法是什么?我考虑的选项是:
答案 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用户身份验证系统: