20

我有 2 个 RESTful Rails 应用程序正在尝试相互交谈。两者都是用 Rails 3(目前是 beta3)编写的。对服务的请求将需要使用 api 密钥,这只是每个请求都需要的参数。我似乎找不到有关如何执行此操作的任何信息。

您通过 site= 方法定义资源连接到的 url。应该有一个等效的 query_params= 方法或类似方法。

我发现一篇与此相关的好博文来自 2008 年 10 月,因此对 Rails 3 并不完全有用。

更新:我有一个想法。小型 Rack 中间件或 Metal 会是解决这个问题的答案吗?它可以通过请求,将它的 api_key 附加上。

4

7 回答 7

22

使用 model#prefix_options ,它是将参数传递到查询字符串的哈希(或者甚至作为 Model.prefix 部分的替代,例如 "/myresource/:param/" 将替换为 prefix_options[:param] 的值。任何在前缀中找不到的哈希键将被添加到查询字符串中,这是我们在您的情况下想要的)。

class Model < ActiveResource::Base
  class << self
    attr_accessor :api_key
  end

  def save
    prefix_options[:api_key] = self.class.api_key
    super
  end
end

Model.site = 'http://yoursite/'
Model.api_key = 'xyz123'
m = Model.new(:field_1 => 'value 1')
# hits http://yoursite:80/models.xml?api_key=xyz123
m.save
于 2011-04-14T07:09:33.253 回答
10

我最近遇到了类似的问题,如果您使用的是 Rails3,它支持使用自定义标头,这使这些情况的生活变得更加轻松。

在您发出请求的一侧,添加

headers['app_key'] = 'Your_App_Key'

到你从 ActiveResource::Base 继承的类

在您是服务器上,对于身份验证,只需将其接收为

request.headers['HTTP_APP_KEY']

例如:

class Magic < ActiveResource::Base
    headers['app_key'] = 'Your_App_Key'
end

现在 Magic.get、Magic.find、Magic.post 都会发送 app_key

于 2011-09-29T10:50:35.607 回答
4

我有更好的解决方案!我尝试在中间件中使用 Rack,但我没有以这种方式找到任何解决方案....

我建议你使用这个模块来覆盖 ActiveReouse::Base 的方法

在 /lib/active_resource/extend/ 目录中添加这个库,不要忘记在config/application.rb中取消注释
“config.autoload_paths += %W(#{config.root}/lib)”

module ActiveResource #:nodoc:
  module Extend
    module AuthWithApi
      module ClassMethods
        def element_path_with_auth(*args)
          element_path_without_auth(*args).concat("?auth_token=#{self.api_key}")
        end
        def new_element_path_with_auth(*args)
          new_element_path_without_auth(*args).concat("?auth_token=#{self.api_key}")
        end
        def collection_path_with_auth(*args)
          collection_path_without_auth(*args).concat("?auth_token=#{self.api_key}")
        end
      end

      def self.included(base)
        base.class_eval do
          extend ClassMethods
          class << self
            alias_method_chain :element_path, :auth
            alias_method_chain :new_element_path, :auth
            alias_method_chain :collection_path, :auth
            attr_accessor :api_key
          end
        end
      end  
    end
  end  
end

在模型中

class Post < ActiveResource::Base
  include ActiveResource::Extend::AuthWithApi

  self.site = "http://application.localhost.com:3000/"
  self.format = :json

  self.api_key = 'jCxKPj8wJJdOnQJB8ERy'

  schema do
    string  :title
    string  :content
  end

end
于 2011-05-25T11:58:48.023 回答
3

基于 Joel Azemar 的回答,但我不得不做出一些改变。首先,在我使用的活动资源 gem(2.3.8)中,没有“new_element_path”,所以别名显然失败了。第二,我更新了令牌添加到查询的方式,因为如果您自己添加更多参数,它就会中断。例如请求http://example.com/api/v1/clients.xml?vat=0123456789?token=xEIx6fBsxy6sKLJMPVM4(注意 ?token=io &token=)

这是我更新的片段 auth_with_api.rb;

module ActiveResource #:nodoc:
  module Extend
    module AuthWithApi
      module ClassMethods
        def element_path_with_auth(id, prefix_options = {}, query_options = nil)
          query_options.merge!({:token => self.api_key})
          element_path_without_auth(id, prefix_options, query_options)
        end
        def collection_path_with_auth(prefix_options = {}, query_options = nil)
          query_options.merge!({:token => self.api_key})
          collection_path_without_auth(prefix_options, query_options)
        end
      end

      def self.included(base)
        base.class_eval do
          extend ClassMethods
          class << self
            alias_method_chain :element_path, :auth
            # alias_method_chain :new_element_path, :auth
            alias_method_chain :collection_path, :auth
            attr_accessor :api_key
          end
        end
      end  
    end
  end
end
于 2012-03-06T11:30:02.867 回答
2

活动资​​源目前没有将 api 密钥传递给远程服务的好方法。将 api_key 作为参数传递会将其添加到远程服务上的对象属性中,我认为这不是您想要的行为。这当然不是我需要的行为

于 2011-01-14T09:55:30.120 回答
2

我建议您有一个基类继承ActiveResource::Base并覆盖self.collection_pathandself.element_path类方法,以始终注入 API KEY,例如:

class Base < ActiveResource::Base
  def self.collection_path(prefix_options = {}, query_options = {})
   super(prefix_options, query_options.merge(api_key: THE_API_KEY))
  end

  def self.element_path(id, prefix_options = {}, query_options = {})
    super(id, prefix_options, query_options.merge(api_key: THE_API_KEY))
  end
end

class User < Base; end

User.all # GET /users/?api_key=THE_API_KEY

这将始终在您的 ActiveResource 方法调用中注入您的 API_KEY。

于 2016-04-29T11:08:05.177 回答
1

一个活动资源对象的行为很像一个(简化的)活动记录对象。如果您希望传递一个新参数,则可以通过将其添加为属性来将其设置在 AR 对象上。例如:

jane = Person.create(:first => 'Jane', :last => 'Doe', :api_key => THE_API_KEY)

它应该与所有其他参数一起传递 api_key 作为参数。

于 2010-12-10T18:25:47.947 回答