在 Rails 日志中显示用户 id/name,许可 gem

Show user id/name in Rails log with Clearance gem

我正在寻找一种方法来在 Rails 日志中的每一行显示当前用户。例如。 [johndoe] 于 2020 年 6 月 7 日开始为 127.0.0.1 获取“/”01:10:33 +0000

一些研究建议使用 rails config.log_tags 设置

(我想出了一个解决方案,但我完全不知道这是否会带来安全后果)。

我发现了一些想法,涉及通过会话和 cookie 查找用户 ID。这对清关无效 req.env 不包含相同的数据。

最终代码

req 是 ActionDispatch::Request 的实例,它是在您加载网页时创建的。您可以在 config.log_tags 中使用 Proc(通常在 config/application.rb 或 config/environments/.rb 中设置),如下所示:

config.log_tags = [
    ->(req) { User.current_user_from_request(req) }
]

User.current_user_from_request(request) 是我创建的一种用于处理吸引用户的方法。这是当前的工作实施:

def self.current_user_from_request(req)
  user = req.env.fetch('rack.request.form_hash', nil)&.fetch('session', nil)&.fetch('email', nil)
  if user.blank?
    Clearance::RackSession.new(Rails.application).call(req.env) unless req.env.key?(:clearance)
    user = req.env[:clearance]&.current_user&.email
    # This line is specific to my implementation. I identify users by their email, and dont need to know the domain  
  end
  user.split("@").first if user.present? 
end

备注

如果您想知道我是如何得出这个结论的,请继续阅读。

我发现许可有 Clearance::RackSession 和方法调用(env) 从 cookie 中读取以前存在的会话并在每次响应时维护 cookie。

此代码为 req.env 添加了一个 :clearance 键

Clearance::RackSession.new(Rails.application).call(req.env)

从这里开始,找到当前用户很简单:

req.env[:clearance]&.current_user

其中 returns User 的实例(继承自 ApplicationRecord)

提出了一些问题

对每个请求执行此操作会导致堆栈太深错误:

Clearance::RackSession.new(Rails.application).call(req.env) unless req.env.key?(:clearance)

这一直有效,直到我注销并重新登录,它引发了 ActionController::InvalidAuthenticityToken 错误。看来我 运行 违反了伪造保护。

在出现此错误时检查 req.env,我发现在 /sessions/sign_in 上提交的表单哈希包含用户的电子邮件,可在此处访问:

req.env['rack.request.form_hash']

因此,如果我首先尝试访问它(这适用于 sign_in 和 sign_out 请求)并回退到上述解决方案(适用于所有其他操作),我们有一个可行的解决方案:

user = req.env.fetch('rack.request.form_hash', nil)&.fetch('session', nil)&.fetch('email', nil)

完整内容请参阅上面的最终代码部分。我还想重复一下 我不知道这个 的安全隐患,或者如果有的话。