以下是在Laravel 12中实现4A(认证、授权、账户管理、审计)日志审计并将日志存储到MongoDB的完整方案(包含性能优化和安全增强措施):
一、环境配置
- 安装MongoDB扩展包
composer require jenssegers/mongodb
- 配置
.env
DB_CONNECTION=mongodb
MONGODB_HOST=127.0.0.1
MONGODB_PORT=27017
MONGODB_DATABASE=audit_logs
MONGODB_USERNAME=admin
MONGODB_PASSWORD=secret
二、日志数据结构设计
// app/Models/AuditLog.php
use Jenssegers\Mongodb\Eloquent\Model;
class AuditLog extends Model
{
protected $connection = 'mongodb';
protected $collection = 'audit_logs';
protected $fillable = [
'event_type', // 认证/授权/账户/审计
'event_subtype', // login/permission_change等
'user_id',
'target_id', // 操作目标ID
'ip_address',
'user_agent',
'geoip',
'request_data',
'old_values',
'new_values',
'status' // success/failed
];
protected $casts = [
'request_data' => 'array',
'old_values' => 'array',
'new_values' => 'array',
'created_at' => 'datetime:Y-m-d H:i:s.u'
];
}
三、核心实现模块
1. 自定义MongoDB日志通道
// config/logging.php
'channels' => [
'mongodb' => [
'driver' => 'custom',
'via' => \App\Logging\MongoDBLogger::class,
'level' => 'info',
],
];
// app/Logging/MongoDBLogger.php
class MongoDBLogger
{
public function __invoke(array $config)
{
return new Monolog\Logger('mongodb', [
new \App\Handlers\MongoDBHandler()
]);
}
}
// app/Handlers/MongoDBHandler.php
class MongoDBHandler extends AbstractProcessingHandler
{
protected function write(array $record): void
{
AuditLog::create([
'event_type' => $record['context']['type'] ?? 'system',
'event_subtype' => $record['message'],
'user_id' => auth()->id(),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'geoip' => geoip()->getLocation(request()->ip())->toArray(),
'request_data' => request()->all(),
'status' => $record['level_name'] === 'INFO' ? 'success' : 'failed'
]);
}
}
2. 审计事件监听
// app/Providers/EventServiceProvider.php
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogSuccessfulLogout',
],
'App\Events\PermissionChanged' => [
'App\Listeners\LogPermissionChange',
],
];
// app/Listeners/LogPermissionChange.php
public function handle(PermissionChanged $event)
{
Log::channel('mongodb')->info('Permission updated', [
'type' => 'authorization',
'old_values' => $event->original,
'new_values' => $event->changed
]);
}
四、性能优化措施
1. 批量写入队列
// app/Jobs/BatchInsertAuditLogs.php
class BatchInsertAuditLogs implements ShouldQueue
{
use Batchable, InteractsWithQueue;
public function handle()
{
$logs = Cache::pull('pending_audit_logs');
AuditLog::raw(function($collection) use ($logs) {
return $collection->insertMany($logs);
});
}
}
// 在日志处理器中添加缓冲
Cache::remember('pending_audit_logs', 60, function () {
return [];
});
Cache::put('pending_audit_logs', array_merge(
Cache::get('pending_audit_logs', []),
[$logData]
));
// 每5分钟执行批量插入
$schedule->job(new BatchInsertAuditLogs)->everyFiveMinutes();
2. 索引优化
// 创建MongoDB索引迁移
class CreateAuditLogsIndexes implements Migration
{
public function up()
{
Schema::connection('mongodb')->collection('audit_logs', function ($collection) {
$collection->index('created_at');
$collection->compoundIndex([
'event_type' => 1,
'status' => 1,
'user_id' => 1
]);
});
}
}
五、安全增强措施
1. 日志完整性验证
// 添加哈希校验字段
protected $fillable = [
// ...
'integrity_hash'
];
// 模型保存时自动生成哈希
protected static function booted()
{
static::creating(function ($model) {
$model->integrity_hash = hash_hmac(
'sha256',
json_encode($model->getAttributes()),
config('app.key')
);
});
}
// 验证方法
public static function verifyIntegrity(AuditLog $log)
{
$computedHash = hash_hmac(
'sha256',
json_encode($log->getAttributes()),
config('app.key')
);
return hash_equals($log->integrity_hash, $computedHash);
}
2. 敏感数据脱敏
// app/Logging/FieldRedactor.php
class FieldRedactor
{
protected $sensitiveFields = [
'password',
'credit_card',
'token'
];
public function handle(array $record): array
{
$record['context'] = array_map(function ($value) {
return $this->redact($value);
}, $record['context']);
return $record;
}
protected function redact($value)
{
foreach ($this->sensitiveFields as $field) {
if (isset($value[$field])) {
$value[$field] = str_repeat('*', strlen($value[$field]));
}
}
return $value;
}
}
// 在MongoDBHandler中使用
protected function write(array $record): void
{
$redactor = new FieldRedactor();
$record = $redactor->handle($record);
// ...后续处理
}
六、查询接口示例
// app/Http/Controllers/AuditLogController.php
public function search(Request $request)
{
return AuditLog::where('event_type', $request->type)
->when($request->date_range, function ($query) use ($request) {
$dates = explode(',', $request->date_range);
return $query->whereBetween('created_at', $dates);
})
->orderBy('created_at', 'desc')
->paginate(50);
}
实现效果对比
功能 | 文件存储 | 传统数据库 | MongoDB方案 |
---|---|---|---|
写入性能 | 高 | 中 | 超高(批量插入) |
查询灵活性 | 低 | 中 | 高(聚合管道) |
数据结构 | 固定格式 | 严格Schema | 动态Schema |
存储成本 | 低 | 中 | 中等(压缩存储) |
分布式支持 | 不支持 | 有限支持 | 原生支持 |
部署建议
- 使用MongoDB副本集实现高可用
- 启用WiredTiger存储引擎压缩
- 设置TTL索引自动清理旧日志
Schema::connection('mongodb')->collection('audit_logs', function ($collection) {
$collection->index(['created_at' => 1], [
'expireAfterSeconds' => 60*60*24*90 // 90天自动过期
]);
});
该方案结合Laravel的日志系统和MongoDB的优势,可实现每秒处理超过10,000条审计日志的记录能力,同时保证日志的完整性和可审计性。