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
答案 0 :(得分:7)
Monkey修补host
类的user
,password
和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
答案 1 :(得分:1)
从Active Resource 4.1.0开始,这些设置是线程本地的,所以这个例子不再导致竞争条件。
如果有人感兴趣,这是相关提交:https://github.com/rails/activeresource/commit/538588ddba9ffc9bf356790e9186dc7e6adad12f