在rails中使用Thread.current []的安全性

时间:2011-10-25 21:47:53

标签: ruby-on-rails thread-safety

我对在Thread.current哈希中存储信息的做法(例如,current_user,当前子域等)持续存在冲突。已经提出该技术作为简化模型层内的后续处理的方法(查询范围,审计等)。

许多人认为这种做法不可接受,因为它破坏了MVC模式。 其他人表达了对方法可靠性/安全性的担忧,我的两部分问题集中在后一方面。

  1. Thread.current哈希是否保证在整个周期内只有一个响应可用且是私有的?

  2. 据我所知,在响应结束时,一个线程可能会被移交给其他传入请求,从而泄露Thread.current中存储的任何信息。是否会在响应结束前清除此类信息(例如,通过从控制器的Thread.current[:user] = nil执行after_filter)来防止此类安全漏洞?

  3. 谢谢! 朱塞佩

4 个答案:

答案 0 :(得分:43)

没有特别的理由远离线程局部变量,主要问题是:

  • 测试它们更难,因为在测试使用它的代码时你必须记住设置线程局部变量
  • 使用线程本地的类需要知道这些对象不是可用但是在线程局部变量中这种间接通常会破坏law of demeter
  • 如果你的框架重用了线程,那么
  • 不清理线程本地可能是一个问题(线程局部变量已经启动,并且依赖 || = 调用初始化变量的代码可能会失败< / LI>

所以,虽然使用它并不是完全没有问题,但最佳方法不是使用它们,而是不时地碰到一个本地线程最简单的墙可能的解决方案,而不需要改变很多代码,你将不得不妥协,有一个不完美的面向对象模型与线程本地或更改相当多的代码来做同样的事情。

所以,这主要是考虑哪个问题对你的案例来说是最好的解决方案,如果你真的要沿着线程本地路径走下去,我肯定会建议你用那些记住的块做到这一点。完成后清理,如下所示:

around_filter :do_with_current_user

def do_with_current_user
    Thread.current[:current_user] = self.current_user
    begin
        yield
    ensure
        Thread.current[:current_user] = nil
    end      
end

这确保在使用此线程之前,线程局部变量在被使用之前被清除。

答案 1 :(得分:21)

这个小宝石确保你的线程/请求局部变量不会在请求之间粘住:https://github.com/steveklabnik/request_store

答案 2 :(得分:7)

接受的答案涵盖了这个问题,但是Rails 5现在提供了一个使用Thread.current的“抽象超类”ActiveSupport::CurrentAttributes

我想我会提供一个链接,作为可能的(unpopular)解决方案。

https://github.com/rails/rails/blob/master/activesupport/lib/active_support/current_attributes.rb

答案 3 :(得分:3)

接受的答案在技术上是准确的,但正如答案中温和地指出的那样,http://m.onkey.org/thread-safety-for-your-rails不是那么温和:

如果您不是必须使用线程本地存储<settings> <mirrors> <mirror> <id>myId</id> <name>MirrorName</name> <url>http://url.com:8081/repositories</url> <mirrorOf>*,!public-snapshots,!public-legacy,!sonar</mirrorOf> </mirror> </mirrors> </settings>

request_store的gem是另一个解决方案(更好),但只是阅读那里的自述文件,以了解更多原因,远离线程本地存储。

几乎总有一种更好的方式。