justgabit / laravel-audit-trail
Laravel 审计跟踪包
Requires
- php: >=7.0.0
- doctrine/dbal: ^2.5
Requires (Dev)
- limedeck/phpunit-detailed-printer: ~4.1
- mockery/mockery: ^1.0@dev
- mopo922/laravel-treats: ^2.0
- orchestra/testbench: ~3.5
- phpunit/phpunit: ~7.0
README
AuditTrail 允许创建任何领域事务的审计跟踪(详细日志)。目前它只与数据库一起工作,但表名和连接名可以自定义,一次可以使用多个不同的表。如果您需要在同一个应用程序中创建不同类型的审计跟踪(系统事务与用户事务等),这将很有用。
发行说明
- 1.1 - 添加了对使用包
mopo922/laravel-treats
的复合主键 Eloquent 模型的支持。 - 1.0 - 首次发布。
安装
composer require justgabit/laravel-audit-trail
AuditTrail 随附两个数据库表,您需要创建这些表才能使用它。安装包后,您需要创建这些表
php artisan migrate
将创建两个表:`audit_trail` 和 `audit_trail_actions`。您可能需要在运行迁移之前通过编辑包默认配置来更改这些表的名称(稍后将有更多介绍)。
概念
审计跟踪是“操作”的时间列表。它旨在读取和写入,但绝对不能更新或删除。系统发生的任何事情都应该永远存在于审计跟踪日志中。
操作代表您想要跟踪的领域事务。换句话说,操作是发生在您应用程序中且您想要有记录的事情。您生成的每个审计跟踪都将始终基于一个操作。以下是一些可能的操作示例:
- 登录
- 登录失败
- 注销
- 记录更新
- 购买邮件发送
每个操作都必须存在于 `audit_trail_actions` 表中,但 AuditTrail 会自动为您更新此表,随着新操作的创建。尽管如此,最好在运行生产环境之前预先填充此表,以避免运行时出现竞争条件。操作表还有一个 `description` 字段,您可以在其中描述该操作表示的内容以及它包含的数据。这是完全可选的,在 AuditTrail 内部根本不使用。
要创建一个操作,您需要创建一个扩展 Mueva\AuditTrail\Action
的类。在 `audit_trail_actions` 表中的操作 id
将从您使用的类名(使用短横线分隔)派生。如果您的类名为 UpdateRecord
,则该操作的 id
将成为 update-record
。
默认情况下,`audit_trail` 表包含以下字段
- id: 表的主键。
- parent_id: 引用 `id` 的外键。当行包含非空 `parent_id` 时,该行被视为子行。这允许跟踪相关事务,例如,单个 HTTP 请求中发生的一切。第一条审计跟踪行获得一个 `id`,接下来的行包含第一条行的 `id` 作为其父级。
- action_id: 引用 `audit_trail_actions` 表的外键。此外键在更新时设置为级联。如果您需要更改操作名称,可以在父表中重命名它,`audit_trail` 表中的所有行将相应地重命名。
- user_id:这表示您系统中用户ID。每个动作很可能是用户交互的结果,因此这允许您跟踪哪个用户触发了该动作。如果您有非用户交互发生的动作,例如cron作业,则可以将此设置为null。
- action_data:这是一个由您的动作类返回的json对象。您可以根据需要填充任何内容,以帮助您了解发生的动作。例如,如果您的动作代表数据库中记录的修改,则可以在该字段中填充更改的diff,甚至记录的“前后”快照。
- action_brief:这是对动作期间发生的事情的简要回忆。例如,如果您的
action_data
包含刚刚更新的完整行,则action_brief
可能包含类似“用户@JohnDoe更新了产品表中的第89行(增加了+2个单位)”的内容。换句话说,这是一个对动作的简短、可读的回忆。 - table_name:如果您的动作代表系统表中的一项更改,则您可以在其中指示更改发生在哪个表中。如果动作代表与表无关的其他事物,则此字段可以为null。
- table_id:与
table_name
类似,这代表发生更改的行的ID。因此,如果您的动作代表在产品表中删除第30行,则table_name
将包含“products”,而table_id
将包含30。 - date:动作发生的日期。
配置
AuditTrail会发布一个配置文件,该文件可以被消费它的应用程序覆盖。为了将配置发布到您的Laravel安装,请执行以下操作:
php artisan vendor:publish
将出现一个菜单,显示所有具有发布内容的包。选择包含Mueva\AuditTrail\AuditTrailServiceProvider
的包。您将可以使用新的配置文件app/config/audit-trail.php
。在里面,您将找到有关每个选项的文档。
创建动作
如前所述,每个动作都必须扩展Mueva\AuditTrail\Action
。了解可用选项的最好地方是类本身。每个方法都有文档,应该能给您一个很好的想法。由于抽象动作类扩展了PHP的JsonSerializable
,您必须实现的方法只有一个,即jsonSerialize()
。此方法的输出将正好是将在audit_trail
表的audit_action
字段中保存的内容。
除了类方法文档中提到的内容外,还有一点需要注意。如果您的动作代表Eloquent模型,则无需覆盖getTableName()
和getTableId()
方法,因为这些可以从Eloquent模型本身推断出来。在这种情况下,只需在getEloquentModel()
中返回模型对象即可。AuditTrail将自动填充table_name
和table_id
字段。
最后,您的动作可能想要隐式地在audit_trail
表中填充额外的字段。这是通过在您的动作中覆盖getExtras()
方法并返回一个数组来实现的,其中键代表字段名,数组值代表字段值。例如,假设您有一个登录动作,它传递一个User模型,并且您的audit_trail
表有一个可空的partner_id
字段,您希望每次执行登录动作时自动填充该字段。在您的登录动作的getExtras()
方法中,您应该编写获取partner_id
的逻辑,基于登录的用户,然后返回以下数组:
<?php public function getExtras(): array { // Here you would write logic to get your partner_id. // Let's assume it is part of your User model for this example. return [ 'partner_id' => $this->user->partner_id ]; }
在上面的示例中,您不需要在创建审计跟踪调用时显式指定partner_id,因为动作将隐式添加该字段。这消除了在审计跟踪调用中获取额外字段的杂乱,并将填充这些字段的责任委托给了动作。
API
使用AuditTrail应该非常直观。假设您已经创建了一个登录操作(稍后会有更多关于如何做到这一点的内容),并且您的登录操作。
在您的类顶部,导入AuditTrail和您的操作类
<?php use Mueva\AuditTrail\AuditTrail; use App\AuditTrailActions\Login;
最详细的功能将是
<?php AuditTrail::create() ->userId(23) ->action(new ProductChanged($productModel)) ->connection('mysql') ->table('my_custom_audit_trail_table') ->execute();
这告诉AuditTrail使用mysql
连接并在my_custom_audit_trail_table
中创建一行。这两个调用都是可选的,当您省略它们时,AuditTrail将使用配置的默认值。在这种情况下,我们指定执行操作的用户的id为23,并且该操作本身代表一个已更改的产品。在此示例中,ProductChange
是一个扩展了Mueva\AuditTrail\Action
的用户定义操作。
您可以为没有由特定用户触发的系统操作调用userId(null)
。此外,userId()
也可以完全省略,AuditTrail将尝试通过内部调用Auth::getUser()
自动检测用户,所以如果您使用Laravel的默认认证机制,省略userId()
可能是一个可行的快捷方式。
对AuditTrail的连续调用
假设您的代码中有三个AuditTrail调用。它们不一定是同一个方法、类或作用域中的
<?php AuditTrail::create() ->action(new Login($user)) ->execute(); AuditTrail::create() ->action(new UpdateCart($product)) ->execute(); AuditTrail::create() ->action(new UpdateCart($product)) ->execute();
在这种情况下,第二个和第三个操作将有一个填充的parent_id
字段,其中包含第一个行的id
。这允许您查询审计跟踪,并获取更多关于触发或与您正在查看的操作相关的操作信息。
如果您希望操作是一个“父”行,即其parent_id
为null
,则可以调用resetParent()
<?php AuditTrail::create() ->action(new Login($user)) ->execute(); AuditTrail::create() ->resetParent() ->action(new UpdateCart($product)) ->execute(); AuditTrail::create() ->action(new UpdateCart($product)) ->execute();
如您所见,第二个调用现在使用了resetParent()
。这意味着第一个和第二个调用将是父行,第三个将第二个行作为其父。一个行只能有一个父。
审计跟踪表中的附加字段
您可以手动向audit_trail
表添加尽可能多的额外字段。在生成审计跟踪时,您可以将额外的参数传递给调用以填充这些字段。假设我们想要跟踪操作发生的虚拟机实例。我们将在audit_trail
表中添加一个instance
列,并填充如下
<?php AuditTrail::create() ->action(new Login($user)) ->instance('i-ys3abwk248sla') ->execute();
您可以链接尽可能多的额外字段。