Впровадження системи аудиту дій користувачів на сайті
Аудит дій - це журналювання всіх значущих подій у системі: хто, що і коли зробив. Необхідно для розслідування інцидентів, відповідності нормативним вимогам (152-ФЗ, GDPR), відстеження змін критичних даних.
Що логувати
Обов'язково:
- Вхід / вихід / невдалі спроби входу
- Зміна пароля, email, номера телефону
- Зміни прав доступу та ролей
- Створення, редагування, видалення критичних сутностей
- Платіжні операції
- Експорт даних
За необхідністю:
- Перегляд персональних даних інших користувачів
- API-запити до адміністративних ендпоінтів
- Зміни конфігурації системи
Структура таблиці аудиту
CREATE TABLE audit_logs (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
event VARCHAR(100) NOT NULL,
subject_type VARCHAR(100),
subject_id BIGINT,
old_values JSONB,
new_values JSONB,
ip_address INET,
user_agent TEXT,
session_id VARCHAR(100),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_audit_user ON audit_logs(user_id);
CREATE INDEX idx_audit_event ON audit_logs(event);
CREATE INDEX idx_audit_subject ON audit_logs(subject_type, subject_id);
CREATE INDEX idx_audit_created ON audit_logs(created_at DESC);
Реалізація через пакет (Laravel)
Пакет owen-it/laravel-auditing - найпоширеніший вибір:
// composer require owen-it/laravel-auditing
use OwenIt\Auditing\Contracts\Auditable;
class User extends Model implements Auditable
{
use \OwenIt\Auditing\Auditable;
protected $auditExclude = ['password', 'remember_token'];
protected $auditEvents = ['created', 'updated', 'deleted'];
}
Користувацька реалізація через Observer
class AuditObserver
{
public function updated(Model $model): void
{
if (!$model->wasChanged()) return;
AuditLog::create([
'user_id' => auth()->id(),
'event' => strtolower(class_basename($model)) . '.updated',
'subject_type' => get_class($model),
'subject_id' => $model->getKey(),
'old_values' => $model->getOriginal(),
'new_values' => $model->getChanges(),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
]);
}
}
User::observe(AuditObserver::class);
Order::observe(AuditObserver::class);
Middleware для аудиту HTTP-запитів
class AuditRequests
{
private array $auditedRoutes = [
'admin.*',
'api.users.*',
'api.settings.*',
];
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
if ($this->shouldAudit($request)) {
AuditLog::create([
'user_id' => auth()->id(),
'event' => 'http.' . strtolower($request->method()),
'new_values' => [
'url' => $request->url(),
'method' => $request->method(),
'status' => $response->status(),
],
'ip_address' => $request->ip(),
]);
}
return $response;
}
}
Аудит входу/виходу
Event::listen(Login::class, function (Login $event) {
AuditLog::create([
'user_id' => $event->user->id,
'event' => 'auth.login',
'new_values' => ['guard' => $event->guard],
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
]);
});
Event::listen(Failed::class, function (Failed $event) {
AuditLog::create([
'user_id' => null,
'event' => 'auth.failed',
'new_values' => ['email' => $event->credentials['email'] ?? null],
'ip_address' => request()->ip(),
]);
});
Продуктивність
Синхронне логування аудиту в кожному запиті впливає на навантаження БД. Рішення:
// Асинхронне логування через черги
dispatch(new WriteAuditLog($data))->onQueue('audit');
// Пакетна вставка - накопичувати в Redis, вивантажувати раз на хвилину
Redis::rpush('audit_queue', json_encode($data));
// Окремена база даних для аудиту
'audit' => [
'driver' => 'pgsql',
'database' => 'audit_db',
]
Зберігання та ротація
// Політика зберігання - видалити записи старіше N років
// Для 152-ФЗ мінімум 3 роки, для PCI DSS - 1 рік
class CleanOldAuditLogs extends Command
{
public function handle(): void
{
AuditLog::where('created_at', '<', now()->subYears(3))->delete();
}
}
Інтерфейс перегляду аудиту
Ключові фільтри в адміністративному інтерфейсі:
- По користувачу
- По типу події
- По часовому діапазону
- По сутності (тип + ID)
- По IP-адресі
Тривалість реалізації
- Базова модель + Observer для ключових сутностей: 2–3 дні
- Повнофункціональна система з очередями, ротацією, UI: 5–7 днів







