9

Active Resource 可以使用在类级别设置的 HTTP 身份验证。例如:

class Resource < ActiveResource::Base
end

Resource.user = 'user'
Resource.password = 'password'

或者

Resource.site = "http://user:password@site.com/"

但是,如果我根据登录的用户使用不同的 HTTP 身份验证呢?如果我更改 Resource.user 和 Resource.password,这是否会导致竞争条件,即来自一个线程的请求突然开始使用请求同时在不同线程中运行的用户的身份验证?或者这是一个非问题(只要我重置请求之间的身份验证),因为 Rails 服务器不是多线程的?

即使没有线程安全问题,如果我未能重置它们,以前用户的凭据将被未来的请求自动使用,这似乎仍然存在风险。

更新:在对 ActiveResource 感到沮丧之后,我编写了自己的 REST 库: https ://github.com/DeepWebTechnologies/well_rested

4

2 回答 2

7

Monkey 修补类的host,userpassword方法ActiveResource::Base

class ActiveResource::Base
  # store the attribute value in a thread local variable
  class << self
    %w(host user password).each do |attr|               

      define_method(attr) do
        Thread.current["active_resource.#{attr}"]
      end

      define_method("#{attr}=") do |val|
        Thread.current["active_resource.#{attr}"] = val
      end
    end
  end
end

现在在每个请求中设置凭据

class ApplicationController < ActionController::Base

  around_filter :set_api_credentials

private 

  # set the credentials in every request
  def set_api_credentials
    ActiveResource::Base.host, 
      ActiveResource::Base.user, 
        ActiveResource::Base.password = current_user_credentials
    yield
  ensure
    ActiveResource::Base.host = 
      ActiveResource::Base.user = 
        ActiveResource::Base.password = nil
  end

  DEFAULT_HOST, DEFAULT_USER, DEFAULT_PASSWORD= [
    "http://www.foo.com", "user1", "user78102" ]

  def current_user_credentials
    current_user.present? ? 
      [ current_user.host, current_user.login, current_user.password] : 
      [ DEFAULT_HOST, DEFAULT_USER, DEFAULT_PASSWORD]
  end

end
于 2011-11-11T03:39:01.330 回答
2

从 Active Resource 4.1.0 开始,这些设置是线程本地的,因此此示例将不再导致竞争条件。

这是相关的提交:https ://github.com/rails/activeresource/commit/538588ddba9ffc9bf356790e9186dc7e6adad12f

于 2016-10-10T13:23:57.500 回答