Подтвердить что ты не робот

Как зарегистрировать имя пользователя в Rails?

Я использую Devise in Rails 3. Я хочу видеть имя current_user в файле production.log.

Я хотел бы настроить рельсы следующим образом:

config.log_tags = [:user_name]
4b9b3361

Ответ 1

Я нашел это небольшое сложное, но рабочее решение.

Warden хранит информацию о пользователе в сеансе, но req.session недоступна для ведения журнала.

Итак, вы должны добавить это в config/application.rb

config.middleware.delete(ActionDispatch::Cookies)
config.middleware.delete(ActionDispatch::Session::CookieStore)
config.middleware.insert_before(Rails::Rack::Logger, ActionDispatch::Session::CookieStore)
config.middleware.insert_before(ActionDispatch::Session::CookieStore, ActionDispatch::Cookies)

Затем создайте файл config/initializers/logging.rb

Rails.configuration.log_tags = [
  proc do |req|
    if req.session["warden.user.user.key"].nil?
      "Anonym"
    else
      "user_id:#{req.session["warden.user.user.key"][0][0]}"
    end
  end
]

Теперь я вижу это для Anonymous:

[Anonym] Served asset ...

и это для пользователя:

[user_id:1] Served asset ...

Ответ 2

Я использовал это решение от Wojtek Kruszewski: https://gist.github.com/WojtekKruszewski

Я немного изменил для моего проекта только идентификатор, но в основном тот же.

# config/application.rb

config.log_tags = [
  ->(req){
    if user_id = WardenTaggedLogger.extract_user_id_from_request(req)
      user_id.to_s
    else
      "?"
    end
  }
]

И создайте этот инициализатор

# initializers/warden_tagged_logger.rb

module WardenTaggedLogger
  def self.extract_user_id_from_request(req)
    session_key = Rails.application.config.session_options[:key]
    session_data = req.cookie_jar.encrypted[session_key]
    warden_data = session_data["warden.user.user.key"]
    warden_data[0][0]
    rescue
      nil
  end
end

Ответ 3

Добавлено 2013-03-07:

В Rails 4 encrypted_cookie_store является хранилищем сеансов по умолчанию. Вот как вы можете получить доступ к данным сеанса:

session_data = req.cookie_jar.signed[ "_qnaire_session" ]

И похоже, что warden_data выглядит по-другому в моем новом приложении, например: [[542], "$2a$10$e5aYxr/PIp6OOj8jzE7mke"], где первый элемент - это идентификатор пользователя.

Вот мой текущий фрагмент: https://gist.github.com/wojt-eu/5109643

Предыдущая версия:

Вот что я придумал:

config.log_tags = [
  :remote_ip,
  ->(req){
    session_data = req.cookie_jar.signed[ "_qnaire_session" ]
    warden_data = session_data["warden.user.provider_user.key"]
    if warden_data
      '#' + warden_data[1][0].to_s
    else
      "guest"
    end
  }
]

_qnaire_session можно заменить на instance.config.session_options[:key] или через singleton: Rails.application.config.session_options[:key]

У меня есть модель ProviderUser, следовательно warden.user.provider_user.key. Я полагаю, что с моделью Пользователя это будет warden.user.user.key.

Это беспорядочно, но это не влияет на обычный процесс проверки подлинности, порядок стека промежуточного программного обеспечения и т.д. Если он ломается во время некоторого обновления, будут затронуты только тегированные журналы, которые я должен быстро заметить при просмотре журналов разработки.

Ответ 4

К сожалению, теги журнала оцениваются только один раз в самом начале делегирования запроса (в Rails::Rack::Logger промежуточном программном обеспечении). На этом этапе контроллер отсутствует, поэтому никакой помощник current_user пока недоступен. Нет еще начальника или даже сеанса, но, по крайней мере, есть cookiejar, поэтому, если вы храните свой session_id, вы можете напрямую восстановить сеанс или log session_id.

config.log_tags = [ lambda { |req| req.cookie_jar["_session_id"].to_s } ]

Я думаю, что лучшей альтернативой является сохранение имени пользователя в cookie непосредственно в log_in и уничтожение его с помощью сеанса.

config.log_tags = [ lambda { |req| req.cookie_jar["user_name"] || 'Noone' } ]

НЕ РАБОТАЕТ:

Но если вы используете devise, он использует промежуточное ПО для раннего набега, поэтому env['warden'] должен быть доступен, так что вы можете попробовать?

config.log_tags = [ lambda { |req| user = req.env['warden'].user; user && user.name || 'Noone'; } ]

Даже без начальника, поскольку у вас есть сеанс, доступный через env['rack.session'], если вы храните идентификатор пользователя в сеансе, вы можете сделать что-то вроде

config.log_tags = [ lambda { |req| user = User.find_by_id(req.env['rack.session']['user_id']); user && user.name || 'Noone'; }

Ответ 5

Вот что я только что добавил в config/initializers/logging.rb:

Rails.configuration.log_tags = [
  :uuid,   # request UUID
  lambda { |req|
    # Credentials are (currently) in the format of:
    #
    #   <session_hash>::<user_id>
    #
    # So we have to split by '::' to obtain the user_id for logging.
    #
    # This will just output "User: nil" if there is no current session.
    "User: #{req.cookies['user_credentials'].to_s.split('::')[1]}"
  }
]

Это для Authlogic. То, что вам нужно сделать, может отличаться, поэтому вам действительно нужно вникнуть и посмотреть, что ваши данные предоставляют вам уже.

Шаг 1:

Посмотрите, что доступно для объекта req. Добавьте это в config/initializers/logging.rb:

Rails.configuration.log_tags = [
  lambda { |req|
    req.inspect
  }
]

Затем нажмите на страницу и посмотрите, что сбрасывается.

Шаг 2: Посмотрите, есть ли в вашем банке cookie достаточно информации, используя ту же технику:

Rails.configuration.log_tags = [
  lambda { |req|
    req.cookies.inspect
  }
]

(нажать на запрос)

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

Ответ 6

Как сказал @viktortron в его ответе в log_tags время инициализации, у нас нет подходящего объекта session, но session_id находится в запрос.

Если вы используете _database session_store_, так как это мой случай, вы можете перестроить сеанс ad-hoc:

session = ActiveRecord::SessionStore::Session.find_by_session_id(request.cookie_jar["_session_id"])

Вот как определяется мой log_tags:

# config/initializers/rails_log.rb
def get_user_id(req)
  session = ActiveRecord::SessionStore::Session.find_by_session_id(req.cookie_jar["_session_id"])
  result = session ? session.data["user_id"] : 0

  "%07d" % result
end

log_tags = []
log_tags << lambda { |req| Time.now.strftime("%F %T.%L") }
log_tags << lambda { |req| req.uuid.first(8) }
log_tags << lambda { |req| get_user_id(req) }

Rails.configuration.log_tags = log_tags

Результат выглядит примерно так:

[2013-01-22 13:51:36.659] [e52435d1] [0036484] <the log line>

Ответ 8

Я использую Swards solution и работает как шарм. Однако используя begin..rescue вместо Hash # has_key? является убийцей производительности

require 'benchmark/ips'

good_hash = { 'warden.user.admin_user.key' => [[1]]}
bad_hash = {}

Benchmark.ips do |x|
  x.report('begin+rescue good hash') { good_hash['warden.user.admin_user.key'][0][0] }
  x.report('has_key good hash') do
    good_hash.has_key?('warden.user.admin_user.key') &&
        good_hash['warden.user.admin_user.key'][0][0]
  end

  x.report('begin+rescue bad hash') { bad_hash['warden.user.admin_user.key'][0][0] rescue nil }
  x.report('has_key bad hash') do
    if bad_hash.has_key?('warden.user.admin_user.key')
      bad_hash['warden.user.admin_user.key'][0][0]
    end
  end

  # Compare the iterations per second of the various reports!
  x.compare!
end

Результаты говорят сами за себя

Comparison:
    has_key bad hash:  4870164.1 i/s
begin+rescue good hash:  3544134.7 i/s - 1.37x slower
   has_key good hash:  2127500.6 i/s - 2.29x slower
begin+rescue bad hash:     4468.2 i/s - 1089.95x slower

Ответ 9

То, что почти сработало для меня (Rails 3.2.22.2), является ответом отсюда: http://benjit.com/rails/logger/2016/02/26/getting-admin-user-into-rails-logfile/

Это предполагает, что объект cookie_jar отвечает на encrypted. Однако для меня это было не так. Что в конечном итоге сработало для меня, выглядит следующим образом:

config/initializers/logging.rb:

Rails.configuration.log_tags = [
  lambda { |req|
    session_key = Rails.application.config.session_options[:key]
    session_data = req.cookie_jar.signed[Rails.application.config.session_options[:key] ]
    warden_data = ( session_data["warden.user.user.key"]|| [[]])
    admin_user = warden_data[0][0]
    "u: #{admin_user || 0}"
  }
]

Ответ 10

Вот файл cookie cookie, который я использую в Rails 5.1, чтобы пометить журналы с помощью user_id, который хранится в файле cookie. Он в основном позволяет мне получить доступ к эквиваленту контроллера session[:user_id] из файла cookie

окружающая среда /production.rb:

config.log_tags = [
  :request_id,
  :remote_ip,
  lambda do |req|
    session_data = CookieDecrypter.new(req).session_data
    "user_id:#{session_data['user_id']}"
  end
]

приложение/модели/cookie_decrypter.rb:

class CookieDecrypter
  attr_reader :request

  def initialize(request)
    @request = request
  end

  def session_data
    cookie = request.cookies[session_key]
    return {} unless cookie.present?
    cookie = CGI::unescape(cookie)
    key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000)
    secret = key_generator.generate_key(salt)[0, ActiveSupport::MessageEncryptor.key_len]
    sign_secret = key_generator.generate_key(signed_salt)
    encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
    encryptor.decrypt_and_verify(cookie) || {}
  end

  private

  def session_key
    Rails.application.config.session_options[:key]
  end

  def secret_key_base
    Rails.application.secrets[:secret_key_base]
  end

  def salt
    Rails.application.config.action_dispatch.encrypted_cookie_salt
  end

  def signed_salt
    Rails.application.config.action_dispatch.encrypted_signed_cookie_salt
  end
end

Ответ 11

Как быстрый и уродливый обходной путь, возможно, можно было бы записать вторую строку после обработки запроса.

Этот 500 ServerError был представлен: # {username}

Ответ 12

Для тех, кто использует команду Redis:: Store @fjuillen, выглядит следующим образом:

redis = Redis::Store.new
redis.select 3 # only if you use a different database
result = redis.get req.cookie_jar["_session_id"]

проверен на рельсах 4.