实例及其关联的审计和模型生命周期管理?

发布于 2024-08-08 14:01:44 字数 792 浏览 4 评论 0原文

我正在尝试编写一个应用程序来跟踪法律案件请求。主要模型是 Case,其中有 has_many 主题、关键字、注释和证据(反过来,有 has_many CustodyLogs)。由于应用程序与法律相关,因此有一些不寻常的要求:

  • 必须记录 CRUD 操作,包括操作是什么、操作者是谁以及操作发生的时间
  • 需要某种方法来验证操作数据(即记录记录的 MD5 校验和)
  • 某些数据应一次性写入(即应用程序可以创建审核日志条目,但此后无法在应用程序内编辑或删除该日志)
  • 对关联对象的更改可能应全程记录筑巢。例如,将 CustodyLog 添加到一段 Evidence 中应该有一个其自身的日志、一个其 Evidence 的日志以及一个父 Case 的日志。这是为了确保 Case 的上次更新时间戳准确反映真实的上次更新,而不仅仅是 Case 模型数据本身上次更改的时间。

我已经完成了一些工作,但遇到了问题。身份验证由外部 Web 单点登录服务处理,因此登录用户 ID 的唯一可见性位于请求变量中。例如,如果我通过回调将审核日志记录放入模型中,我可以相当确定所有数据修改都已记录,但模型对请求变量不可见,因此我无法记录用户 ID。这还确保记录对状态机(当前使用 state_machine 插件)的更改。

另一方面,如果我将审核日志记录放在应用程序控制器中,我将无法确保记录所有 CRUD 操作(例如,不会记录 Case 模型中调用 subject.create 的代码) 。我还认为我会失去状态变化。

有没有办法确保所有 CRUD 操作都记录在整个关联树中,以便记录登录用户的用户 ID?

I am trying to write an application to track legal case requests. The main model is Case, which has_many Subjects, Keywords, Notes, and Evidences (which, in turn, has_many CustodyLogs). Since the application is legal-related, there are some requirements that are out of the ordinary:

  • CRUD operations must be logged, including what the operation was, who the actor was, and when the operation occurred
  • There needs to be some way to validate the data (i.e. recording MD5 checksums of records)
  • Some data should be write-once (i.e. the app can create an audit log entry, but that log cannot be edited or deleted from within the application thereafter)
  • Changes to associated objects probably should be logged throughout the nesting. For example, adding a CustodyLog to a piece of Evidence should have a log for itself, a log for it's Evidence, and a log for the parent Case. This is to ensure that the last update timestamp for the Case accurately reflects the real last update, and not just the last time that the Case model data itself changed.

I've got bits of this working, but I'm running into a problem. Authentication is being handled by an external web single-sign-on service, so the only visibility to the ID of the logged in user is in a request variable. If I put audit logging in the model, through a callback, for example, I can be fairly sure that all data modifications are logged, but the model has no visibility to the request variables, so I can't log the user ID. This also ensures that changes to the state machine (currently using state_machine plugin) get logged.

If, on the other hand, I put the audit logging in the application controller, I lose the ability to be sure that all CRUD operations are logged (code in the Case model calling Subject.create, for example, wouldn't be logged). I also think that I'd lose state changes.

Is there a way to be sure that all CRUD operations are logged throughout the association tree such that the user ID of the logged in user is recorded?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鲜肉鲜肉永远不皱 2024-08-15 14:01:44

CRUD 操作必须被记录,包括操作内容、执行者是谁以及操作发生的时间。

这可以通过 ActiveRecord::Callbacks 和 attr_accessor 字段来解决。

在任何需要记录的模型中添加以下内容。

  attr_accessor :modifier_id, :modifier

  valiadate :valid_user
  before_validate :populate_modifier
  before_save :write_save_attempted_to_audit_log
  after_save :write_save_completed_to_audit_log

  def populate_modifier
    self.modifier = User.find_by_id(modifier_id) unless modifier
  end 

  def valid_user
    unless modifier
      errors.add(:modifiers_user_id, "Unknown user attempted to modify this record") 
      write_unauthorized_modification_to_audit_log
    end
  end

  def write_save_attempted_to_audit_log
    # announce that user is attempting to save a record with timestamp to audit log
    # use ActiveRecord::Dirty.changes to show the change the might be made
  end

  def write_save_competed_to_audit_log
    # announce that user has successfully changed the record with timestamp to audit log
  end

  def write_unauthorized_modification
    # announce that a change was attempted without a user
  end

因为您可能会在一些模型中使用它,所以您可以将其抽象为一个插件,并仅在需要时使用 audit_changes 等方法调用添加它。请参阅任何 act_as 插件以获取有关如何实现此目标的灵感。

在控制器中,您需要记住在尝试保存之前添加 @thing.modifier = @current_user


需要有某种方法来验证数据(即记录记录的 MD5 校验和)

至于操作的校验和...?您可以重写检查以以一致的方式打印包含记录中所有信息的字符串,然后为其生成校验和。当您这样做时,不妨将其添加到审核日志中,作为写入日志方法的一部分。


某些数据应该一次性写入(即应用程序可以创建审核日志条目,但此后无法在应用程序内编辑或删除该日志)将

每个访问日志写入具有确定性名称的单独文件("/ logs/audits/#{class}/#{id}/#{timestamp}") 并在保存后删除写入权限。 File.chmod(0555, access_log_file)


对关联对象的更改可能应该在整个嵌套过程中记录下来。例如,将 CustodyLog 添加到一段 Evidence 中应该有一个其自身的日志、一个其 Evidence 的日志以及一个父 Case 的日志。这是为了确保 Case 的上次更新时间戳准确反映真实的上次更新,而不仅仅是 Case 模型数据本身上次更改的时间。

至于第四个要求。如果您在任何嵌套关系上使用accepts_nested_attributes_for,这将自动纳入我的解决方案中。并且:自动保存=>对于“belongs_to”关系为 true。


如果您将校验和保存到审核日志中,则可以将检查滚动到 before_save 方法中,以确保您正在处理的对象未被篡改。只需检查对象的最新审核日志并匹配校验和即可。

CRUD operations must be logged, including what the operation was, who the actor was, and when the operation occurred

This can be addressed with an ActiveRecord::Callbacks and an attr_accessor field.

In any of the models that need to be logged add the following.

  attr_accessor :modifier_id, :modifier

  valiadate :valid_user
  before_validate :populate_modifier
  before_save :write_save_attempted_to_audit_log
  after_save :write_save_completed_to_audit_log

  def populate_modifier
    self.modifier = User.find_by_id(modifier_id) unless modifier
  end 

  def valid_user
    unless modifier
      errors.add(:modifiers_user_id, "Unknown user attempted to modify this record") 
      write_unauthorized_modification_to_audit_log
    end
  end

  def write_save_attempted_to_audit_log
    # announce that user is attempting to save a record with timestamp to audit log
    # use ActiveRecord::Dirty.changes to show the change the might be made
  end

  def write_save_competed_to_audit_log
    # announce that user has successfully changed the record with timestamp to audit log
  end

  def write_unauthorized_modification
    # announce that a change was attempted without a user
  end

Because you're likely to use this in a few models you can abstract it into a plugin, and add it only with needed with a method call like audit_changes. See any of the acts_as plugins for inspiration on how to accomplish this.

In the controllers you will need to remember to add @thing.modifier = @current_user before attempting to save.


There needs to be some way to validate the data (i.e. recording MD5 checksums of records)

As for a checksum... of an operation? You could override inspect to print a string containing all the information in the record in a consistent fashion and then generate a checksum for that. While you're at it, might as well add it to the to the audit log as part of the writing to log methods.


Some data should be write-once (i.e. the app can create an audit log entry, but that log cannot be edited or deleted from within the application thereafter)

Write each access log as a separate file with a deterministic name ("/logs/audits/#{class}/#{id}/#{timestamp}") and remove the write permission once it's saved. File.chmod(0555, access_log_file)


Changes to associated objects probably should be logged throughout the nesting. For example, adding a CustodyLog to a piece of Evidence should have a log for itself, a log for it's Evidence, and a log for the parent Case. This is to ensure that the last update timestamp for the Case accurately reflects the real last update, and not just the last time that the Case model data itself changed.

As for the 4th requirement. That will automatically get rolled into my solution for the first if you use accepts_nested_attributes_for on any of your nested relationships. And :autosave => true for belongs_to relationships.


If you're saving checksums into audit logs, you can roll a check into the before_save method to ensure the object you're working on, was has not been tampered with. Just by checking the latest audit log for the object and matching up the checksums.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文