web-dev-qa-db-ja.com

railsでのThread.current []使用の安全性

情報をThread.currentハッシュ(たとえば、current_user、現在のサブドメインなど)に保存する方法について、相反する意見が出続けています。この手法は、モデルレイヤー内の以降の処理(クエリのスコープ、監査など)を簡素化する方法として提案されています。

多くの人は、MVCパターンに違反するため、この慣行は受け入れられないと考えています。他の人はアプローチの信頼性/安全性について懸念を表明しており、私の2部構成の質問は後者の側面に焦点を当てています。

  1. Thread.currentハッシュは、そのサイクル全体を通じて、1つの応答に対してのみ使用可能でプライベートであることが保証されていますか?

  2. 応答の最後にあるスレッドが他の着信要求に渡される可能性があり、それによりThread.currentに格納されている情報が漏洩する可能性があることを理解しています。そのようなセキュリティ侵害を防ぐには、応答の終了前にそのような情報をクリアすること(たとえば、コントローラーのThread.current[:user] = nilからafter_filterを実行すること)で十分ですか?

ありがとう!ジュゼッペ

75
Giuseppe

スレッドローカル変数を避ける特別な理由はありません。主な問題は次のとおりです。

  • それらを使用するコードをテストするときに、スレッドローカル変数を設定することを忘れないでください。
  • スレッドローカルを使用するクラスは、これらのオブジェクトがavailableではなく、スレッドローカル変数の内部であり、この種の間接が通常 demeterの法則を破るという知識が必要です。
  • フレームワークがスレッドを再利用する場合、スレッドローカルをクリーンアップしないことが問題になる場合があります(スレッドローカル変数が既に開始され、変数を初期化するための =呼び出しに失敗する可能性があります)

したがって、使用するのは完全に問題ではありませんが、bestアプローチはそれらを使用することではありませんが、時々、スレッドローカルが最も単純な解決策になる壁にぶつかる非常に多くのコードを変更し、妥協する必要があります。スレッドローカルで完全ではないオブジェクト指向モデルを使用するか、同じことを行うために非常に多くのコードを変更します。

だから、それは主にあなたのケースにとって最善の解決策になるだろうと考えている問題であり、あなたが本当にスレッドローカルパスを下っているなら、私はあなたが後にクリーンアップすることを覚えているブロックでそれを行うことを確かに勧めます次のように行われます。

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

これにより、このスレッドがリサイクルされる場合、使用される前にスレッドローカル変数がクリーンアップされます。

45

この小さな宝石は、スレッド/リクエストのローカル変数がリクエスト間で固定されないようにします: https://github.com/steveklabnik/request_store

21
Dejan Simic

受け入れられた答えは質問をカバーしますが、Rails 5は「抽象スーパークラス」を提供します ActiveSupport :: CurrentAttributes Thread.currentを使用します。

可能な( 不人気 )解決策として、それへのリンクを提供すると思いました。

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

9
Jonny

受け入れられた回答は技術的に正確ですが、回答で穏やかに指摘されているように、 http://m.onkey.org/thread-safety-for-your-Rails それほど穏やかではありません:

スレッドローカルストレージを使用しない、Thread.current絶対に必要ない場合

request_store は別の解決策です(より良い)が、スレッドローカルストレージから離れるより多くの理由のためにそこのreadmeを読んでください。

ほとんどの場合、より良い方法があります。

3
Tom Harrison