4

我正在使用 devise 和devise-basecamper对基于子域的 Web 应用程序进行身份验证。

我想允许超级用户访问任何帐户(基本上是任何子域)。

我不确定我将如何实现这一点,以便用户可以通过任何子域进行身份验证,因为用户当前已针对特定子域进行验证。

有任何想法吗?

4

6 回答 6

8

如果我正确理解您的需求,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]

现在不仅需要在日志中,而且在任何其他事情上都需要。这一切都取决于您的应用程序,维护起来可能会变得非常乏味。

免责声明

  • 这是伪代码,不安全,如果您选择此解决方案,您需要强制执行安全性
  • 我回答你的问题是因为你问了,但我个人的建议是:不要实施这个解决方案,因为它看起来像一个很大的安全漏洞,你应该让管理员用户在他们成为某人后注销并登录别的
于 2013-07-23T01:07:29.890 回答
3

我在我的应用程序中使用以下解决方案。

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
于 2013-06-05T16:52:09.427 回答
1

设计文档有一节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
于 2013-06-07T11:55:34.293 回答
1

身份验证和授权是两个不同的操作,我认为必须单独完成。使用设计方法进行身份验证,并实现您的自定义代码进行授权。

例子:

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
于 2013-07-23T11:46:35.270 回答
0

我认为您必须拆分授权和身份验证。身份验证验证某个登录帐户是否有效,授权将一组资源分配给用户。

如果我有通用授权,你可以在 ApplicationController 中创建一个方法,如果用户可以访问它,则返回一个(过滤的)资源。或者,如果用户只有查看自己资源的权限,您可以为每个按 user_id 限定范围的活动记录模型添加范围。

于 2013-06-11T18:32:01.367 回答
0

最终,我不得不从设计默认创建的用户表中删除唯一电子邮件索引,并在用户表上添加一个新的唯一索引,其中包含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
于 2013-07-29T01:01:31.867 回答