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

5
我需要关于如何在Ruby中实现“客户端-服务器”Web应用程序的建议。任何指南和最佳实践都将不胜感激。我对Ruby的方式以及所需的gems感兴趣,因为这是一个期望的平台,并且对于实现这些功能的一般方法和逻辑也感兴趣。
很遗憾,我既不是出色的Ruby程序员,也不是有多年经验的熟练系统设计师,所以我真的需要你的帮助,因为我仍然希望这个事情最终会发光。
应用程序的当前外观应该是这样的:
DB + Auth DB <-> API App <-> Other Apps:
- DB-一个数据库或一组数据库,每个用户组(地区)都有一个DB。 - 认证DB-另一个DB,包含个人用户数据和登录信息,即使主数据库分布在各个地区,也可能只有一个。 - API App-这个东西维护所有围绕数据、访问控制和翻译的逻辑,可能要有一个翻译基础供所有应用程序使用。 - 其他应用程序-API绑定的大量不同应用程序,这可以是向API插入某些用户数据的数据提供程序,以及不同种类的UI。 所有应用程序都不能拥有自己的用户相关信息存储,并仅通过API处理数据。
API App:看起来最好的工具是Sinatra。问题是:
1. 如何以清晰的方式组织API? Rails为模型和控制器提供了良好的REST路径设置和文件夹结构。有什么技巧或gems可以改善API构建体验吗? 2. 如何维护访问权限?鉴于API客户端将是Web应用程序本身,Warden并不是一个好选择。因此,我需要某种身份验证令牌。如何实现?一些自定义OAuth提供者?问题是,我不喜欢通过API存储和传递会话cookie的想法,所以需要每个请求传递某种访问令牌。
其他应用程序:主要是基于Web的UI。这部分的逻辑选择是Rails。主要问题是如何实现客户端验证检查。Devise很酷,但是否可能使其与令牌配合使用,或者更适合的工具是什么?

Travis在那里有一些示例代码。例如,它有一个单点登录应用程序和一个名为Travis Chat的应用程序,可以与其连接:https://github.com/travis - three
1个回答

5

好的,这可能会有点长:

如果您已经熟悉Rails,可以看看Rails API gem。该项目致力于从Rails中删除不需要为基于JSON的RESTful API所需的额外冗余。

这听起来很顺畅,但它也有缺点。首先,您必须阅读所有基本的rails功能,您可能已经习惯了,例如respond_to。这可能有点棘手,但当您找到最初提供通常捆绑在ActionController :: Base 中的Rails功能的Rails模块时,这是相当直接的。

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

初始情况

我们有一个基本完成的Rails应用程序。一切都很好,但基本上是单片式的。所有内容都由Rails框架提供。幸运的是,所有模型逻辑都捆绑在名为core的gem中。该应用程序基本上允许已登录的客户创建产品,然后通过最终用户视图进行搜索。

目标是为此提供一个RESTful API,该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 Token来保护您的API。如果您想了解更多关于API安全方面的知识,我建议您查看Ryan Bates在Railscasts中的指南
实质上,在ApplicationController中提供一个before过滤器,就像这样:
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模板,建议添加JBuilder (Railscast)。

很好,但客户端怎么办?

个人而言,在选择客户端方面有很多选择。最终我发现选择取决于你最喜欢什么。我个人推荐在Rails API之上添加一个小型的node.js层,然后在其前面使用基于backbone.js的单页应用程序。如果你想的话,你也可以尝试AngularJS。您还可以构建另一个Rails应用程序并从控制器操作中调用API。

这也取决于您要针对哪个平台-可以考虑iOS / Android的原生应用程序。

我做出的选择是node.js + backbone。目前对我和项目来说最有意义。该node层本质上持有与API通信所需的令牌,而backbone应用程序则具有一个小型库以与节点层通信。但它可能是一个双刃剑,取决于您的API有多么复杂。对于一个小例子,这似乎很好,但是如果只是把backbone应用程序的调用放到Rails API中,那么就会有很多代码重复。

认证

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

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

希望我提供了一些见解。

P.S.:如果您想测试API,我强烈推荐httpie (它超棒!)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接