是否可以基于每个用户设置Active Resource HTTP身份验证的线程安全?

时间:2011-11-11 00:08:00

标签: ruby-on-rails thread-safety activeresource class-variables

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

2 个答案:

答案 0 :(得分:7)

Monkey修补host类的userpasswordActiveResource::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

答案 1 :(得分:1)

从Active Resource 4.1.0开始,这些设置是线程本地的,所以这个例子不再导致竞争条件。

如果有人感兴趣,这是相关提交:https://github.com/rails/activeresource/commit/538588ddba9ffc9bf356790e9186dc7e6adad12f