如何在Ruby(Rails / Sinatra)中实现客户端 - 服务器API和授权?

时间:2013-02-01 10:47:35

标签: ruby api authentication sinatra

我需要一个关于如何在ruby中实现“客户端 - 服务器”Web应用程序的建议。任何指南和最佳实践都非常感谢。我对Ruby方式和所需的宝石感兴趣,因为它是一个理想的平台,以及实现这些东西的一般方式和逻辑。

我不是一个优秀的红宝石程序员或熟练的系统设计师,可悲地多年,所以我真的需要你的帮助,因为我仍然希望这件事最终会闪耀。

应用程序的当前外观应如下所示:

DB + Auth DB< - > API App< - >其他应用:

  • DB - 一个数据库或一组数据库,其中一个数据库用于用户组(区域)。
  • Auth DB - 一个包含个人用户数据和登录信息的数据库,即使主数据库在区域之间分割,也可能单一。
  • API应用程序 - 这个东西维护着围绕数据,访问控制和翻译的所有逻辑,可能为所有应用程序提供一个翻译基础。
  • 其他应用程序 - 一堆不同的应用程序,与API绑定,这可能是数据提供程序,它使用某些用户的一些数据和不同类型的UI来搜索API。所有应用程序都没有自己的用户相关信息存储空间,只能通过API处理数据。

API应用看起来是制作Sinatra的最佳工具。问题是:

  1. 如何以清晰的方式组织API? Rails为模型和控制器提供了很好的REST路径设置和文件夹结构。任何提高API构建经验的提示或宝石?
  2. 如何维持访问? Warden看起来不是一个好选择,因为API客户端本身就是Web应用程序。所以我需要某种身份验证令牌。怎么可能呢?某种自定义OAuth提供商?问题是,我不喜欢通过API存储和传递会话cookie的想法,每个请求传递一些访问令牌。这也是
  3. 其他应用主要是基于网络的用户界面。这部分的逻辑选择是Rails。主要问题是如何实现客户端身份验证。设计很酷,但它是否可以使用令牌,或者它是更合适的工具?

1 个答案:

答案 0 :(得分:5)

好的,这会有点长:

如果您已熟悉Rails,可以查看Rails API gem。该项目致力于从Rails中删除其他基于JSON的RESTful API不需要的内容。

这可能听起来很顺利,但它有它的缺点。首先,您已经阅读了您可能习惯的基本轨道功能所需的所有内容,例如: respond_to。这可能有点棘手,但是当您发现哪些rails模块最初提供了ActionController::Base中通常捆绑在Rails中的功能时,这非常简单。

话虽如此,让我举一个例子,说明我上周出于好奇心做的一个小型API项目:

初始状况

我们有一个主要完成的Rails应用程序。一切正常,但它基本上是单片的。一切都由Rails框架提供。对我们来说幸运的是,所有模型逻辑都捆绑在一个名为core的宝石中。该应用程序本质上允许登录的客户创建可通过最终用户视图搜索的产品。

目标是为此提供RESTful API,它可以更有效地处理并发和更大的数据文件(即CSV,XLS)。

介绍Rails API

设计目标让我来到Rails API gem。基本安装在Rails中工作,除了脚本称为rails-api,即:

rails-api new jsonapi

我在这里的优点是我可以使用其他应用程序中的core,但没有什么能阻止我将自己的模型引入jsonapi应用程序。

话虽这么说,你可以做所有标准的Rails好东西,比如路由等。它遵循相同的约定。然后,标准路线最初只对JSON做出反应,有时可能会有点混乱。

让我举一个处理产品的API控制器的例子:

class ProductsController < ApplicationController
  include ActionController::HttpAuthentication::Token
  before_filter :find_product, :except => [:create, :index]

  def index
    render :json => @products
  end

  def create
    @product = product.new params[:product]

    if @product.save
      render :json => @product, :status => :created
    else
      render :json => @product.errors, :status => :unprocessable_entity
    end
  end

  def show
    render :json => @product
  end

  def update
    if @product.update_attributes params[:product]
      render :json => @product, :status => :ok
    else
      render :json => @product.errors
    end
  end

  def destroy
    if @product.destroy
      render :json => @product, :status => :ok
    else
      render :json => {:note => I18n.t("messages.deletion_impossible")}, :status => :unprocessable_entity
    end
  end

protected
  def find_product
    @product = Product.find params[:id]
  end
end

没什么特别的。唯一需要注意的是显式包含ActionController::HttpAuthentication::Token的第二行。这样可以通过HTTP令牌保护您的aPI。如果您想了解有关保护API的更多信息,我建议Ryan Bates'Guide on Railscasts

至关重要的是,您在ApplicationController中提供了一个前置过滤器,如下所示:

class ApplicationController < ActionController::API  
  include ActionController::HttpAuthentication::Token::ControllerMethods
  [...]
  before_filter :restrict_access
  [...]
  def restrict_access
    authenticate_or_request_with_http_token do |token, options|
      # see if key is valid.
    end
  end
end

再次注意第二行,您必须手动包含ControllerMethods,否则控制器不会知道authenticate_or_request_with_http_token

扩展

您可能知道基于Rails约定扩展API。它的工作方式完全相同,但默认情况下有些东西是故意丢失的。如果您在JSON模板中需要更多灵活性,我建议添加JBuilderRailscast)。

很好,但客户呢?

就个人而言,在客户方面有很多选择。最终我发现它归结为你最喜欢的东西。我个人可以在Rails API之上推荐一个小的node.js层,然后在它前面获得基于backbone.js的单页面应用程序。如果您愿意,也可以尝试AngularJS。您还可以围绕它构建另一个Rails应用程序,并在控制器操作中调用API。

它还取决于您想要定位的平台 - 想到iOS / Android的本机应用程序。

我做的选择是node.js + backbone。它目前对我和项目最有意义。节点层基本上保存与API通信所必需的令牌,并且主干应用程序具有与节点层通信的小型库。但它可能是一把双刃剑,取决于你的API有多复杂。对于一个小例子,这看起来很好,但是可能有很多代码重复只是为了将来自主干应用程序的调用放到Rails API中。

验证

对于身份验证,您可以创建基于客户的API密钥(令牌),然后将控制器逻辑限制为仅接受该密钥允许的数据操作。您可以通过节点层管理会话。编辑:这是授权,而不是身份验证。实际上没有什么能阻止你使用Authlogic和Rails API - 我没有测试它,但它应该可以工作。

我承认我还没有完成这部分 - 我希望其他人可以回答这个架构问题: - )

我希望我能提供一些见解。

P.S。:如果你想测试你的API,我强烈推荐httpie(太棒了!)