diff --git a/README.md b/README.md index 456b61a..a24aed7 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ $apiLog->causer; // the model that made the request Sensitive values are **redacted by default** before a log is stored: common credential fields (`password`, `token`, `access_token`, …) in the request data, query string and response data, and sensitive request headers (`Authorization`, `Cookie`, `X-Api-Key`, …) are replaced with `[REDACTED]`. -To customize the redaction lists or the replacement string, publish the config file: +To customize the authentication guard, the redaction lists or the replacement string, publish the config file: ``` php artisan vendor:publish --provider="CodeTech\ApiLogs\Providers\ApiLogServiceProvider" --tag=config @@ -92,6 +92,8 @@ Then adjust `config/api-logs.php`: ```php return [ + 'guard' => null, + 'redact' => [ 'replacement' => '[REDACTED]', 'keys' => ['password', 'access_token' /* , ... */], @@ -100,6 +102,8 @@ return [ ]; ``` +`guard` pins the authentication guard used to resolve the user a logged request is attributed to (e.g. `'sanctum'`). When `null`, the request's default guard is used — the one set by the `auth` middleware, or the application's default guard. + `keys` are matched case-insensitively and recursively against the request payload, query string and response data; `headers` are matched against request header names. ## Testing & code quality diff --git a/config/api-logs.php b/config/api-logs.php index 5b2b6c2..cb0a68d 100644 --- a/config/api-logs.php +++ b/config/api-logs.php @@ -2,6 +2,19 @@ return [ + /* + |-------------------------------------------------------------------------- + | Authentication Guard + |-------------------------------------------------------------------------- + | + | The authentication guard used to resolve the user a logged request is + | attributed to. When null, the request's default guard is used (the one + | set by the auth middleware, or the application's default guard). + | + */ + + 'guard' => null, + /* |-------------------------------------------------------------------------- | Redaction diff --git a/src/Http/Middleware/LogApiRequest.php b/src/Http/Middleware/LogApiRequest.php index 02d9897..98154ca 100644 --- a/src/Http/Middleware/LogApiRequest.php +++ b/src/Http/Middleware/LogApiRequest.php @@ -25,7 +25,7 @@ public function handle(Request $request, Closure $next): Response */ public function terminate(Request $request, Response $response): void { - $user = auth()->user(); + $user = auth()->guard(config('api-logs.guard'))->user(); if ($user === null || ! method_exists($user, 'apiLogs')) { return; diff --git a/tests/Feature/LogApiRequestMiddlewareTest.php b/tests/Feature/LogApiRequestMiddlewareTest.php index 9f44121..d3c9a88 100644 --- a/tests/Feature/LogApiRequestMiddlewareTest.php +++ b/tests/Feature/LogApiRequestMiddlewareTest.php @@ -99,6 +99,49 @@ public function test_redaction_lists_are_configurable(): void $this->assertSame('kept-now', $log->request_data['password']); } + public function test_configured_guard_is_used_to_resolve_the_user(): void + { + $this->defineApiGuard(); + config()->set('api-logs.guard', 'api'); + + $user = User::create([ + 'name' => 'Test User', + 'email' => 'user@example.com', + 'password' => 'secret', + ]); + + $this->actingAs($user, 'api') + ->postJson('/api/echo', ['name' => 'value']) + ->assertOk(); + + $this->assertSame(1, ApiLog::count()); + $this->assertTrue(ApiLog::first()->causer->is($user)); + } + + public function test_request_is_not_logged_when_configured_guard_is_unauthenticated(): void + { + $this->defineApiGuard(); + config()->set('api-logs.guard', 'api'); + + $user = User::create([ + 'name' => 'Test User', + 'email' => 'user@example.com', + 'password' => 'secret', + ]); + + $this->actingAs($user, 'web') + ->postJson('/api/echo', ['name' => 'value']) + ->assertOk(); + + $this->assertSame(0, ApiLog::count()); + } + + private function defineApiGuard(): void + { + config()->set('auth.guards.api', ['driver' => 'session', 'provider' => 'users']); + config()->set('auth.providers.users', ['driver' => 'eloquent', 'model' => User::class]); + } + public function test_unauthenticated_request_passes_through_and_is_not_logged(): void { $this->getJson('/api/ping')