0

在我的 Rails 应用程序中,我users有谁可以拥有很多projects,而后者又可以拥有很多tasks.

模型:

class Task < ActiveRecord::Base

  attr_accessible :project_id

end

控制器:

class TasksController < ApplicationController

  def create
    @task = current_user.tasks.build(params[:task])    
    if @task.save
      flash[:success] = "Task saved."
      redirect_to edit_task_path(@task)
    else
      render :new
    end
  end

  def update
    if @task.update_attributes(params[:task])
      flash[:success] = "Task updated."
      redirect_to edit_task_path(@task)
    else
      render :edit
    end
  end

end

Rails 中确保用户A不能为用户B创建任务的标准做法是什么?

现在,我project_ids通过表单中的选择框选项限制用户可用的选项。但是,这很容易通过浏览器控制台被黑客入侵,而且根本不安全。

如何改进?

谢谢你的帮助。

4

2 回答 2

1

我会使用 before 过滤器来检查所需项目是否属于当前用户:

class TasksController < ApplicationController
  before_filter :find_project, only: :create

  def create
    @task = @project.tasks.build(params[:task])    
    if @task.save
      flash[:success] = "Task saved."
      redirect_to edit_task_path(@task)
    else
      render :new
    end
  end

  private

  def find_project
    @project = current_user.projects.where( id: params[ :task ][ :project_id ] ).first
    redirect_to( root_path, notice: 'No such project' ) unless @project
  end
end

因此,如果给定的 project_id 与属于当前用户的项目不匹配,他将被重定向出去。

但是,一种更方便的方式是使用嵌套资源:

resources :projects
  resources :tasks, shallow: true
end

你会有这样的路线:

GET /projects/1/tasks (index)
GET /projects/1/tasks/new (new)
POST /projects/1/tasks (create)
GET /tasks/1 (show)
GET /tasks/1/edit (edit)
PUT /tasks/1 (update)
DELETE /tasks/1 (destroy)

但这不会有太大差异,您仍然需要检索 Post :

class TasksController < ApplicationController
  before_filter :find_project, only: [ :index, :new, :create ]
  before_filter :find_task, only: [ :show, :edit, :update, :delete ]

  # other actions

  def create
    @task = @project.tasks.build(params[:task])    
    if @task.save
      flash[:success] = "Task saved."
      redirect_to edit_task_path(@task)
    else
      render :new
    end
  end

  private

  def find_project
    @project = current_user.projects.where( id: params[ :project_id ] ).first
    redirect_to( root_path, notice: 'No such project' ) unless @project
  end

  def find_task
    @task = current_user.tasks.where( id: params[ :id ] ).first
    redirect_to( root_path, notice: 'No such task' ) unless @task
  end
end
于 2013-09-26T14:01:17.307 回答
1

#find最简单的做法是确定查找范围并利用可以 raise的事实RecordNotFound。Rails 将挽救该异常并为您呈现 404。

class TasksController < ApplicationController
  helper_method :project

  def create
    @task = project.tasks.build(params[:task])    
    if @task.save
      flash[:success] = "Task saved."
      redirect_to edit_task_path(@task)
    else
      render :new
    end
  end

  private

  def project
    @project ||= current_user.projects.find(params[:task][:project_id])
  end
end

我还要补充一点,您还应该将 URL 限定在它所属的项目下的任务的范围内。比如/projects/:project_id/tasks/:id使用嵌套资源。

于 2013-09-26T14:17:28.137 回答