【问题标题】:Securing a rails API with shallow routes使用浅层路由保护 Rails API
【发布时间】:2014-05-15 19:36:55
【问题描述】:

我正在构建一个 JSON api,它将成为另一个 rails 站点的数据源(使用 devise 进行身份验证),并且具有基本的令牌身份验证工作。 API 还将负责向移动应用程序提供数据。

在 API 中,我有如下模型: 用户、书籍和章节 一个用户 has_many :books,一本书 has_many :chapters。在我的路线文件中,我有

shallow do
  resources :users do
    resources :books do
      resources :chapters
    end
  end
end

这会导致如下路线:

/users/:user_id , /users/:user_id/books
/books/:book_id , /books/:book_id/chapters
/chapters/:chapter_id 

即“浅路径”,而不是 /users/:user_id/books/:book_id/chapters/:chapter_id

我想知道我应该如何验证这些,因为章节不属于用户。这不仅仅是检查 user_id 的情况(因为这是书籍模型的属性)。

# chapters_controller
def show
  @chapter = Chapter.find(params[:id])
end

然后我是否必须获取@chapter 的书,然后检查它的 user_id? 不知怎的,我觉得不太对劲。我走错方向了吗?

感谢阅读!

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-4


    【解决方案1】:

    我发现一种可行的技术是让控制器建立一个模型范围,以限制对当前经过身份验证的用户可见/可更新/可破坏的内容。

    我首先使用request_store gem 在我的User 模型上设置当前用户和来自控制器的请求信息,这只是线程本地存储上的一个小垫片,并进行了一些清理。

    这使得用户和请求信息可以通过User 类从我的任何模型中获得。我有User.current、User.request 和User.location 在我需要的地方可用。

    一旦对用户进行身份验证,您的控制器只需设置User.current 和User.request。这在您的模型中构建范围时非常有用,因为它们可以限制当前用户可以访问的内容。

    您可以在模型上定义一个范围,例如 visible,它可以在相关模型上执行 where(:owner => User.current.id) 或类似的操作,以限制当前模型的可见/可更新/可销毁的内容。

    然后您的控制器只需调用SomeModel.visible、SomeModel.updateable、SomeModel.destroyable,它将获得一个仅限于可以读取/写入/销毁的范围。任何基于该模型范围的find,只有在模型确实在用户的范围规则内时才会成功!

    示例用户模型:

    # models/user.rb
    require 'request_store'
    
    class User
    
      def self.current
        RequestStore.store[:current_user]
      end
    
      def self.current=(user)
        RequestStore.store[:current_user] = user
      end
    
      def self.request
        RequestStore.store[:current_request]
      end
    
      def self.request=(request)
        # stash the request so things like IP address and GEO-IP based location is available to other models
        RequestStore.store[:current_request] = request
      end
    
      def self.location
        # resolve the location just once per request
        RequestStore.store[:current_location] ||= self.request.try(:location)
      end
    end
    

    【讨论】:

    • 目前尚不清楚此解决方案如何允许您授权依赖于父模型且不限于用户的模型。在这种情况下,鉴于只有章节父级的范围仅限于用户,并且路径很浅,您将如何授权用户更新章节......
    • 最初的问题主要是关于 api 用户的身份验证。我明确避免在我的回答中定义模型,因为它们是特定于 ORM 的。没有详细说明如何授权用户、如何分配/定义角色。问题中没有提供模型。控制器负责根据定义的任何业务规则执行访问控制。章节控制器需要将章节范围仅限于当前经过身份验证的用户有权访问的书籍。它非常特定于 orm/model,只需使用适当的 ORM 查询范围即可。
    • 我很欣赏这一点,但问题显然是关于如何授权不直接作用于用户的资源。 OP 正在询问他是否必须通过章节来阅读这本书并将其用户 ID 与当前用户 ID 进行比较。我不明白你是如何回答这个问题的。至少以目前的形式,你的答案对我来说不是很清楚。
    • 我会考虑在控制器中添加关于范围访问权限的注释。
    • 那太好了。感谢您抽出宝贵时间。
    猜你喜欢
    • 2011-11-19
    • 2011-10-16
    • 1970-01-01
    • 2019-09-13
    • 2021-07-18
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    相关资源
    最近更新 更多