Безопасность использования Thread.current [] в рельсах

Я продолжаю получать противоречивые мнения о практике хранения информации в хеше Thread.current (например, current_user, текущий поддомен и т.д.). Этот метод был предложен как способ упростить последующую обработку на уровне модели (область охвата запроса, аудит и т.д.).

Многие считают практику неприемлемой, поскольку она нарушает шаблон MVC. Другие выражают озабоченность по поводу надежности/безопасности подхода, и мой вопрос из двух частей посвящен второму аспекту.

  • Является ли хэш Thread.current гарантированным доступным и конфиденциальным для одного и только одного ответа на протяжении всего цикла?

  • Я понимаю, что поток, в конце ответа, вполне может быть передан другим входящим запросам, тем самым утечка любой информации, хранящейся в Thread.current. Будет ли устранение такой информации до конца ответа (например, путем выполнения Thread.current[:user] = nil с контроллера after_filter) для предотвращения такого нарушения безопасности?

Спасибо! Giuseppe

Ответ 1

Не существует конкретной причины, чтобы держаться подальше от локальных переменных, основными проблемами являются:

  • сложнее их протестировать, так как вам придется не забывать устанавливать локальные переменные потока при тестировании кода, который его использует. Классы
  • которые используют локаторы потоков, нуждаются в знаниях о том, что эти объекты не являются доступными для них, но внутри локальной переменной потока, и этот тип косвенности обычно нарушает закон demeter
  • не очистка локаторов потоков может быть проблемой, если ваша инфраструктура повторно использует потоки (уже была инициирована локальная переменная потока, а код, который полагается на || =, вызовы для инициализации переменных могут завершиться неудачно

Итак, хотя это не совсем возможно, подход лучший не использует их, но время от времени вы попадаете в стену, где локальный поток будет самым простым возможное решение, не изменяя довольно много кода, и вам придется идти на компромисс, иметь менее совершенную объектно-ориентированную модель с потоком локального или менять довольно много кода, чтобы сделать то же самое.

Итак, это в основном вопрос мышления, который будет лучшим решением для вашего дела, и если вы действительно сходите по нит-локальному пути, я бы посоветовал вам сделать это с блоками, которые помнят очистите их после завершения, например:

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

Это гарантирует, что локальная переменная потока очищается до использования, если этот поток повторно используется.

Ответ 2

Этот маленький жемчуг гарантирует, что локальные переменные потока/запроса не встанут между запросами: https://github.com/steveklabnik/request_store

Ответ 3

Принятый ответ технически точен, но как указано в ответе мягко, а http://m.onkey.org/thread-safety-for-your-rails не так мягко:

Не используйте локальное хранилище потоков Thread.current, если вам не нужно

Драгоценный камень для request_store - это еще одно решение (лучше), но просто прочитайте readme там по другим причинам, чтобы держаться подальше от локального хранилища потоков.

Существует почти всегда лучший способ.