Ruby-on-rails Rails 中 Thread.current[] 使用的安全性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7896298/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Safety of Thread.current[] usage in rails
提问by Giuseppe
I keep getting conflicting opinions on the practice of storing information in the Thread.currenthash (e.g., the current_user, the current subdomain, etc.). The technique has been proposed as a way to simplify later processing within the model layer (query scoping, auditing, etc.).
关于在Thread.current哈希中存储信息的做法(例如,current_user、当前子域等),我不断收到相互矛盾的意见。该技术已被提议作为一种简化模型层(查询范围、审计等)内后续处理的方法。
- Why are my thread variables intermittent in Rails?
- Alternative to using Thread.current in API wrapper for Rails
- Are Thread.current[] values and class level attributes safe to use in rails?
- 为什么我的线程变量在 Rails 中是间歇性的?
- 在 Rails 的 API 包装器中使用 Thread.current 的替代方法
- 在 Rails 中使用 Thread.current[] 值和类级别属性是否安全?
Many consider the practice unacceptable because it breaks the MVC pattern. Others express concerns about reliability/safety of the approach, and my 2-part question focuses on the latter aspect.
许多人认为这种做法是不可接受的,因为它打破了 MVC 模式。其他人表达了对该方法的可靠性/安全性的担忧,而我的 2 部分问题侧重于后一个方面。
Is the
Thread.currenthash guaranteed to be available and private to one and only one response, throughout its entire cycle?I understand that a thread, at the end of a response, may well be handed over to other incoming requests, thereby leaking any information stored in
Thread.current. Would clearing such information before the end of the response (e.g. by executingThread.current[:user] = nilfrom a controller'safter_filter) suffice in preventing such security breach?
Thread.current散列是否保证在整个周期中对一个且只有一个响应可用和私有?我知道一个线程在响应结束时很可能会被移交给其他传入的请求,从而泄漏存储在
Thread.current. 在响应结束之前清除此类信息(例如通过Thread.current[:user] = nil从控制器执行after_filter)是否足以防止此类安全漏洞?
Thanks! Giuseppe
谢谢!朱塞佩
采纳答案by Maurício Linhares
There is not an specific reason to stay away from thread-local variables, the main issues are:
没有特定的理由远离线程局部变量,主要问题是:
- it's harder to test them, as you will have to remember to set the thread-local variables when you're testing out code that uses it
- classes that use thread locals will need knowledge that these objects are not availableto them but inside a thread-local variable and this kind of indirection usually breaks the law of demeter
- not cleaning up thread-locals might be an issue if your framework reuses threads (the thread-local variable would be already initiated and code that relies on ||=calls to initialize variables might fail
- 测试它们更难,因为您必须记住在测试使用它的代码时设置线程局部变量
- 使用线程局部变量的类需要知道这些对象对它们不可用,而是在线程局部变量中,而这种间接性通常违反了demeter 定律
- 如果您的框架重用线程,则不清理线程局部变量可能是一个问题(线程局部变量已经启动,依赖||=调用初始化变量的代码可能会失败
So, while it's not completely out of question to use, the bestapproach is not to use them, but from time to time you hit a wall where a thread local is going to be the simplest possible solution without changing quite a lot of code and you will have to compromise, have a less than perfect object oriented model with the thread local or changing quite a lot of code to do the same.
因此,虽然使用并非完全没有问题,但最好的方法是不要使用它们,但有时您会碰壁,在这种情况下,本地线程将成为最简单的解决方案,而无需更改大量代码和你将不得不妥协,有一个不太完美的面向对象模型,线程本地或更改相当多的代码来做同样的事情。
So, it's mostly a matter of thinking which is going to be the best solution for your case and if you're really going down the thread-local path, I'd surely advise you to do it with blocks that remember to clean up after they are done, like the following:
所以,这主要是一个思考的问题,哪个将是您的情况的最佳解决方案,如果您真的沿着线程本地路径走,我肯定会建议您使用记得清理之后的块来做它们完成了,如下所示:
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
This ensures the thread local variable is cleaned up before being used if this thread is recycled.
如果此线程被回收,这将确保线程局部变量在使用前被清除。
回答by Dejan Simic
This little gem ensures your thread/request local variables not stick between requests: https://github.com/steveklabnik/request_store
这个小宝石确保您的线程/请求局部变量不会在请求之间粘连:https: //github.com/steveklabnik/request_store
回答by Jonny
The accepted answer covers the question but as Rails 5 now provides a "Abstract super class" ActiveSupport::CurrentAttributeswhich uses Thread.current.
接受的答案涵盖了这个问题,但随着 Rails 5 现在提供了一个使用 Thread.current的“抽象超类” ActiveSupport::CurrentAttributes。
I thought I would provide a link to that as a possible(unpopular) solution.
我想我会提供一个链接作为可能的(不受欢迎的)解决方案。
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/current_attributes.rb
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/current_attributes.rb
回答by Tom Harrison
The accepted answer is technically accurate, but as pointed out in the answer gently, and in http://m.onkey.org/thread-safety-for-your-railsnot so gently:
接受的答案在技术上是准确的,但正如答案中所指出的那样,在http://m.onkey.org/thread-safety-for-your-rails 中不是那么温和:
Don't use thread local storage, Thread.currentif you don't absolutely have to
Thread.current如果您不是绝对必须,请不要使用线程本地存储
The gem for request_storeis another solution (better) but just read the readme there for more reasons to stay away from thread local storage.
gem forrequest_store是另一种解决方案(更好),但只需阅读那里的自述文件,就有更多理由远离线程本地存储。
There is almost always a better way.
几乎总是有更好的方法。

