前言:我正在使用设计进行身份验证。
我正试图阻止未经授权的用户查看,编辑或更新其他用户的信息。我最关心的是用户将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
答案 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_to
和render
我的建议是将所有重定向逻辑放入before_filter