从路由引用current_user时的RESTful路由最佳实践?

时间:2015-06-15 00:23:15

标签: ruby-on-rails rest

我为用户提供了典型的RESTful路由:

/user/:id
/user/:id/edit
/user/:id/newsfeed

但是,只有当id等于current_user的id时,才能访问/user/:id/edit路由。因为我只希望current_user有权编辑其配置文件。我不希望其他用户能够编辑不属于他们的配置文件。

处理这种情况的最佳做法通常是什么?

我应该按原样离开路线,如果是current_user.id != param[:id],则强制前端客户端调用api来跟踪登录用户的ID吗?

我应该制作一条特殊路线/user/self/edit并在控制器中检查是否param[:id] == 'self'

10 个答案:

答案 0 :(得分:13)

我会为当前的用户个人资料操作添加特殊路线,在这种情况下,您不必检查任何内容。只需加载并显示当前用户的数据。例如:

/my-profile/edit
/my-profile/newsfeed

这不是RESTful,但你不必额外检查以保持代码清洁。

如果您仍然需要(或想拥有)严格的RESTful路由,那么我将使用before_filter并检查id = current_user.id。如果没有,则返回401或403。

答案 1 :(得分:5)

  

我只希望current_user有权编辑其个人资料。一世   不希望其他用户能够编辑不属于的个人资料   它们。

我建议使用一些授权宝石,例如pundit

示例代码:

class UserPolicy
  attr_reader :current_user, :model

  def initialize(current_user, model)
    @current_user = current_user
    @user = model
  end

  def edit?
    @current_user == @user
  end
end

同样使用Devise之类的身份验证宝石,只有current_user(登录的用户)才能访问和编辑他们的个人资料

答案 2 :(得分:2)

我会说你正确地做到了,只是保持你现在的路线。您应该做的是在控制器中添加限制。我假设你正在使用Rails,并在使用users_controller。

class UsersController < ApplicationController::Base
  def edit
    if current_user.id == params[:id]
      # do your work
    else
      render :404
    end
  end
end

或者您可以通过将限制转换为回调来清理控制器:

class UsersController < ApplicationController::Base
  before_filter :restrict_user, only: [:edit]

  def edit
    # do your work
  end

  private
  def restrict_user
    render :404 unless current_user.id == params[:id]
  end
end

答案 3 :(得分:2)

您可以在初始化后添加gem "cancancan" ....

    class Ability
        include CanCan::Ability

        def initialize(user)

            can :update, User do |user|
                 user.id == params[:id]
            end
        end
    end

然后将此authorize! :edit, @user添加到您的更新操作

答案 4 :(得分:2)

您将需要在所有user_controller方法中添加授权代码作为另一条评论建议。通常我在用户只应编辑自己的配置文件的应用程序中做的我为用户添加/ profile路由以编辑自己的配置文件,然后在main / users /:id / * routes上添加逻辑以防止非-admin用户访问这些路由。

答案 5 :(得分:2)

用户可以查看他的个人资料/users/1或修改他的个人资料/users/1/edit。从用户的角度来看,这个URL绝对没问题。

没有可能导致用户编辑其他用户的链接。您试图涵盖不同的情况:当有人手动尝试制作URL并访问另一个帐户时。我不会称他们为黑客,但从技术上讲他们是 - 试图利用您的网站传递限制的用户。

你不必担心&#34;黑客&#34;方便。我总是在current_user操作中使用edit,因此无论他的个人资料是什么,都无法编辑错误的个人资料。

def edit
  @user = current_user
end

另外,我需要提一下,您还应该通过此类检查来涵盖update行动。使用edit,您只能获取数据(可能只有广泛的公开数据,除非您在edit模板中放置了结算信息或纯文本密码)。但是使用update,您实际上可以更改数据,这可能会更具破坏性。

答案 6 :(得分:2)

因为似乎唯一可用的用户资源应该是经过身份验证的用户,我认为解决此问题的最佳方法是

GET /user
PUT /user
GET /user/newsfeed

如果您希望将来扩展api用法,以便一个用户可以访问其他用户资源,那么您需要一个包含用户ID的解决方案。在这里介绍“自我”的路线也是有意义的。但是,您还必须在服务器端实施访问检查。

GET /user/id/:id
PUT /user/id/:id
GET /user/id/:id/newsfeed

GET /user/self
PUT /user/self
GET /user/self/newsfeed

但我认为你应该保持尽可能简单

为了进一步调查,我会提出像http://apigee.com/about/resources/ebooks/web-api-design这样的书籍,它们可以很好地介绍API设计

答案 7 :(得分:1)

由于您只关心为当前经过身份验证的用户提供RESTful端点 ,该用户在您的控制器中可用current_user,我说您不需要{{1} } identifier参数。我建议使用以下路线:

id

答案 8 :(得分:0)

你应该保持网址不变。身份验证和授权是一个单独的问题。 'current_user'是指经过身份验证以访问api的用户。 url中的id标识'current_user'正在工作的资源,因此他是否有权访问该资源是授权的关注点。因此,您应该在api权限中添加current_user.id != param[:id](如您所述)并将403状态代码作为回应。

答案 9 :(得分:-1)

你应该使用这条路线:

PUT /user/me

请注意,无需“编辑”:您应该使用PUT方法。

此外,您应该明确定义我上面写的路线,而不是检查是否id == 'self'