我正在使用 devise 和devise-basecamper对基于子域的 Web 应用程序进行身份验证。
我想允许超级用户访问任何帐户(基本上是任何子域)。
我不确定我将如何实现这一点,以便用户可以通过任何子域进行身份验证,因为用户当前已针对特定子域进行验证。
有任何想法吗?
我正在使用 devise 和devise-basecamper对基于子域的 Web 应用程序进行身份验证。
我想允许超级用户访问任何帐户(基本上是任何子域)。
我不确定我将如何实现这一点,以便用户可以通过任何子域进行身份验证,因为用户当前已针对特定子域进行验证。
有任何想法吗?
如果我正确理解您的需求,st 方法是执行以下步骤:
成为用户
如果您需要以其他用户的身份执行操作,或者“查看他所看到的”,这是必要的
首先你需要实现设计的官方方式(这是伪代码,我让你适应你的个人情况)
# the usage of session[:original_user_id] is explained later
def become
if admin? or session[:original_user_id]
if session[:original_user_id] == params[:id]
session[:original_user_id] = nil # This is intended to clean-up stuff after you become your self back again
else
session[:original_user_id] = current_user.id # This is to record your real identity while you are becoming some one else
end
sign_in(:user, User.find(params[:id]))
end
end
如您所见,我们“成为”了被请求的用户,而且我们在会话中记录了您的真实user.id
. 请注意,如果您选择此解决方案,您必须设置 rails 以将会话数据保存在数据库中,以避免这些数据在野生 cookie 中漫游。
重新成为你自己
其次,您需要在您的视图中的某个地方链接“变回自己”,我建议将标题作为一个好位置
if session[:original_user_id]
link_to 'Be my self', become_path(session[:original_user_id])
end
这将创建一个链接,仅对“成为”其他人的管理员可见,并且该链接将允许您“成为”具有与您的真实用户帐户对应的 ID 的用户。点击它会带回你的真实身份。
在您成为其他用户时保留您的管理员权限
然后你想保留你的管理员权限,我们需要欺骗系统让他相信你“成为”的用户是管理员,但我们必须保护应用程序,这样它就不会对这个“假权限”进行不必要的保存在数据库中
在您的应用程序控制器中,实现一个前置过滤器
before_filter :fake_admin
def fake_admin
if session[:original_user_id]
current_user.fake_admin = true
current_user.admin = true
end
end
然后为了保护您的用户记录以获得不需要的管理员权限,在您的用户模型中,您可以设置一个 before_save_filter(或 before_validation_filter,取决于您的架构)
before_save :check_for_fake_admin
def check_for_fake_admin
self.admin = false if self.fake_admin
end
避免在日志中提及您成为的用户的名称
您别无选择,只能手动破解应用程序中需要提及管理员名称而不是您“成为”名称的用户的所有位置。如果记录中的 Axample不为零,则updated_by
必须设置为session[:original_user_id]
现在不仅需要在日志中,而且在任何其他事情上都需要。这一切都取决于您的应用程序,维护起来可能会变得非常乏味。
免责声明
我在我的应用程序中使用以下解决方案。
class RandomController < ApplicationController
before_filter :authenticate_user!, unless: :super_user
end
class ApplicationController < ActionController::Base
def super_user?
current_user.email == 'super@example.com'
end
end
设计文档有一节How To: Sign in as another user if you are an admin,其中解释了如何实现您想要做的事情。
这是文档说您需要做的要点:
class AdminController < ApplicationController
before_filter authenticate_user!
def become
return unless current_user.is_an_admin?
sign_in(:user, User.find(params[:id]))
redirect_to root_url # or user_root_url
end
end
身份验证和授权是两个不同的操作,我认为必须单独完成。使用设计方法进行身份验证,并实现您的自定义代码进行授权。
例子:
class SomeController < ApplicationController
before_filter :authenticate_user!
before_filter :authorize_user
end
class ApplicationController < ActionController::Base
def authorize_user
unless current_user.admin? or request.subdomain == current_user.subdomain# logic to check if user is authorized
redirect_to root_path, :notice => "Access denied"
end
end
end
我认为您必须拆分授权和身份验证。身份验证验证某个登录帐户是否有效,授权将一组资源分配给用户。
如果我有通用授权,你可以在 ApplicationController 中创建一个方法,如果用户可以访问它,则返回一个(过滤的)资源。或者,如果用户只有查看自己资源的权限,您可以为每个按 user_id 限定范围的活动记录模型添加范围。
最终,我不得不从设计默认创建的用户表中删除唯一电子邮件索引,并在用户表上添加一个新的唯一索引,其中包含email
, 和account_id
列。这将允许我为创建的每个帐户创建一个用户(我称之为 support@example.com)。
这是我的迁移
def change
remove_index :users, :email
add_index :users, [:email, :account_id], :unique => true
end
这是我after_save
添加到account
模型中的回调。
class Account < ActiveRecord::Base
after_save :create_support_user
private
# A callback that creates a support user after an account is created.
def create_support_user
user = User.new
user.email = "support@example.com"
user.password = "test1234"
user.password_confirmation = "test1234"
user.account_id = self.id
user.name = "Support"
user.skip_confirmation!
user.admin = true
user.save
end
end