3

前言:我正在使用设计进行身份验证。

我试图阻止未经授权的用户查看、编辑或更新其他用户的信息。我最担心的是用户将 DOM 中的表单修改为另一个用户的 ID,填写表单,然后单击更新。我已经在 SO 上专门阅读过类似下面的内容应该可以工作,但事实并非如此。SO 上的一篇文章建议将该validate_current_user方法移至公共领域,但这也不起作用。

有什么明显的我做错了吗?或者是否有更好的方法来解决我正在尝试做的事情,无论是使用设计还是其他东西?

我的UsersController样子是这样的:

class UsersController < ApplicationController
  before_filter :authenticate_admin!, :only => [:new, :create, :destroy]
  before_filter :redirect_guests

  def index
    redirect_to current_user unless current_user.try(:admin?)

    if params[:approved] == "false"
      @users = User.find_all_by_approved(false)
    else
      @users = User.all
    end
  end

  def show
    @user = User.find(params[:id])
    validate_current_user
    @user
  end

  def new
    @user = User.new
  end

  def edit
    @user = User.find(params[:id])
    validate_current_user
    @user
  end

  def create
    @user = User.new(params[:user])

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, :notice => 'User was successfully created.' }
      else
        format.html { render :action => "new" }
      end
    end
  end

  def update
    @user = User.find(params[:id])

    validate_current_user

    respond_to do |format|
      if @user.update_attributes(params[:user])
        format.html { redirect_to @user, :notice => 'User was successfully updated.' }
      else
        format.html { render :action => "edit" }
      end
    end
  end

  private

  def redirect_guests
    redirect_to new_user_session_path if current_user.nil?
  end

  def validate_current_user
    if current_user && current_user != @user && !current_user.try(:admin?)
      return redirect_to(current_user)
    end
  end

end

authenticate_admin!方法如下所示:

  def authenticate_admin!
    return redirect_to new_user_session_path if current_user.nil?

    unless current_user.try(:admin?)
      flash[:error] = "Unauthorized access!"
      redirect_to root_path
    end
  end

编辑 —— 你是什么意思“它不起作用?”

为了帮助澄清,当我尝试“破解”另一个用户的帐户时出现此错误:

在此操作中多次调用渲染和/或重定向。请注意,您只能调用渲染或重定向,并且每个操作最多调用一次。另请注意,重定向和渲染都不会终止操作的执行,因此如果您想在重定向后退出操作,则需要执行“redirect_to(...) and return”之类的操作。

如果我将方法代码内联在各个控制器操作中,它们确实可以工作。但是,我不想这样做,因为它不干。

我还应该指定我已经尝试过:

def validate_current_user
  if current_user && current_user != @user && !current_user.try(:admin?)
     redirect_to(current_user) and return
  end
end
4

4 回答 4

3

如果您考虑一下,return在私有方法中只是退出方法并将控制权传递回控制器 - 它不会退出操作。如果您想退出该操作,您必须再次返回

例如,你可以有这样的东西:

class PostsController < ApplicationController
  def show
    return if redirect_guest_posts(params[:guest], params[:id])
    ...
  end

  private

  def redirect_guest_post(author_is_guest, post_id)
    redirect_to special_guest_post_path(post_id) if author_is_guest
  end
end

如果 params[:guest] 存在且不为 false,则私有方法返回一些真实的内容,并且 #show 操作退出。如果条件失败,则返回 nil,然后操作继续。

于 2013-09-08T02:29:46.147 回答
2

您正在尝试并且希望在每次操作之前授权用户。我建议您使用标准 gem,例如 CanCan 或 declarative_authorization。

继续采用这种方法,您最终可能会重新发明轮子。

如果您决定使用 cancan,您所要做的就是在ability.rb 文件中添加权限(由 rails cancan:install 生成)

可以 [:read,:write,:destroy], :role => "admin"

而在控制器中只需添加 load_and_authorize_resource (可以过滤)。它将检查用户是否具有当前操作的权限。如果用户没有权限,那么它会抛出一个 403 禁止期望,可以在 ApplicationController 中捕获并适当处理。

于 2013-04-13T17:20:47.190 回答
1

尝试,

before_filter :redirect_guests, :except => [:new, :create, :destroy]

应该管用。

这是因为您在 authenticate_admin 中使用了两次重定向!和 redirect_guests 用于新建、创建和销毁操作。

于 2013-04-13T17:10:09.077 回答
0

“在此操作中多次调用渲染和/或重定向。请注意,您只能调用渲染或重定向,并且每个操作最多调用一次。”

这就是错误的原因。在show方法中,如果您既不是该帐户的所有者也不是管理员,您将面临两个操作:redirect_torender

我的建议是将所有重定向逻辑放入before_filter

于 2013-04-13T17:28:41.597 回答