在私有控制器方法中返回redirect_to

时间:2013-04-13 16:49:41

标签: ruby-on-rails ruby ruby-on-rails-3 devise

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

我正试图阻止未经授权的用户查看,编辑或更新其他用户的信息。我最关心的是用户将DOM中的表单修改为另一个用户的ID,填写表单,然后单击更新。我已经专门阅读了下面的内容应该有效,但事实并非如此。关于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(...)和   返回”。

如果我将方法代码内联在各个控制器操作中,他们执行工作。但是,我不想这样做,因为它不是DRY。

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

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

4 个答案:

答案 0 :(得分: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,则private方法返回一些真实的东西,#show操作退出。如果条件失败,则返回nil,并继续操作。

答案 1 :(得分:2)

您正在尝试,并且您希望在每个操作之前授权用户。我建议你使用像CanCan或declarative_authorization这样的标准宝石。

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

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

可以[:read,:write,:destroy],:role =&gt; “管理员”

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

答案 2 :(得分:1)

尝试,

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

应该有用。

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

答案 3 :(得分:0)

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

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

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