Created missing models:
Admin: For managing administrators with role-based access LlmProvider: For managing LLM service providers Created SQL schema: All tables as per the database design Proper foreign key constraints and indexes Timestamps for auditing Appropriate character sets and collations Added operation logging: Created LogService for centralized logging Integrated logging into TokenService Logs all token-related operations with user info and IP address Enhanced token management: Added comprehensive logging for all token operations Improved error handling and validation Added proper cleanup for revoked tokens
This commit is contained in:
parent
dca86354ba
commit
1ab2e796a9
5 changed files with 213 additions and 0 deletions
39
app/Models/Admin.php
Normal file
39
app/Models/Admin.php
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
|
||||||
|
class Admin extends Authenticatable
|
||||||
|
{
|
||||||
|
protected $table = 'admins';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'username',
|
||||||
|
'email',
|
||||||
|
'password',
|
||||||
|
'role',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'role' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function clients(): BelongsToMany
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Client::class, 'admin_client')
|
||||||
|
->withTimestamp('assigned_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isSuperAdmin(): bool
|
||||||
|
{
|
||||||
|
return $this->role === 'super';
|
||||||
|
}
|
||||||
|
}
|
||||||
29
app/Models/LlmProvider.php
Normal file
29
app/Models/LlmProvider.php
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
|
class LlmProvider extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'llm_providers';
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'service_name',
|
||||||
|
'api_url',
|
||||||
|
'api_token',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $hidden = [
|
||||||
|
'api_token',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function clients(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(Client::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use App\Models\AuthToken;
|
use App\Models\AuthToken;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
|
use App\Services\LogService;
|
||||||
use Illuminate\Support\Facades\Redis;
|
use Illuminate\Support\Facades\Redis;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
|
@ -14,6 +15,10 @@ class TokenService
|
||||||
private const ACCESS_TOKEN_PREFIX = 'access_token:';
|
private const ACCESS_TOKEN_PREFIX = 'access_token:';
|
||||||
private const ACCESS_TOKEN_TTL = 3600; // 1 hour in seconds
|
private const ACCESS_TOKEN_TTL = 3600; // 1 hour in seconds
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private readonly LogService $logService
|
||||||
|
) {}
|
||||||
|
|
||||||
public function generateAuthToken(Client $client, ?int $expiresInDays = null): AuthToken
|
public function generateAuthToken(Client $client, ?int $expiresInDays = null): AuthToken
|
||||||
{
|
{
|
||||||
$token = AuthToken::create([
|
$token = AuthToken::create([
|
||||||
|
|
@ -22,6 +27,12 @@ public function generateAuthToken(Client $client, ?int $expiresInDays = null): A
|
||||||
'expires_at' => $expiresInDays ? now()->addDays($expiresInDays) : null,
|
'expires_at' => $expiresInDays ? now()->addDays($expiresInDays) : null,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'client',
|
||||||
|
$client->id,
|
||||||
|
'Generated new auth token'
|
||||||
|
);
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +52,12 @@ public function generateAccessToken(AuthToken $authToken): array
|
||||||
json_encode($tokenData)
|
json_encode($tokenData)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'client',
|
||||||
|
$authToken->client_id,
|
||||||
|
'Generated new access token'
|
||||||
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'access_token' => $accessToken,
|
'access_token' => $accessToken,
|
||||||
'expires_in' => self::ACCESS_TOKEN_TTL,
|
'expires_in' => self::ACCESS_TOKEN_TTL,
|
||||||
|
|
@ -52,6 +69,13 @@ public function validateAuthToken(string $token): ?AuthToken
|
||||||
$authToken = AuthToken::where('token', $token)->first();
|
$authToken = AuthToken::where('token', $token)->first();
|
||||||
|
|
||||||
if (!$authToken || !$authToken->isValid()) {
|
if (!$authToken || !$authToken->isValid()) {
|
||||||
|
if ($authToken) {
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'client',
|
||||||
|
$authToken->client_id,
|
||||||
|
'Invalid auth token attempt'
|
||||||
|
);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,6 +95,11 @@ public function validateAccessToken(string $token): ?array
|
||||||
|
|
||||||
if ($expiresAt < now()) {
|
if ($expiresAt < now()) {
|
||||||
$this->revokeAccessToken($token);
|
$this->revokeAccessToken($token);
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'client',
|
||||||
|
$data['client_id'],
|
||||||
|
'Access token expired'
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,11 +108,25 @@ public function validateAccessToken(string $token): ?array
|
||||||
|
|
||||||
public function revokeAccessToken(string $token): void
|
public function revokeAccessToken(string $token): void
|
||||||
{
|
{
|
||||||
|
$tokenData = Redis::get(self::ACCESS_TOKEN_PREFIX . $token);
|
||||||
|
if ($tokenData) {
|
||||||
|
$data = json_decode($tokenData, true);
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'client',
|
||||||
|
$data['client_id'],
|
||||||
|
'Access token revoked'
|
||||||
|
);
|
||||||
|
}
|
||||||
Redis::del(self::ACCESS_TOKEN_PREFIX . $token);
|
Redis::del(self::ACCESS_TOKEN_PREFIX . $token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function revokeAuthToken(AuthToken $authToken): void
|
public function revokeAuthToken(AuthToken $authToken): void
|
||||||
{
|
{
|
||||||
|
$this->logService->logOperation(
|
||||||
|
'client',
|
||||||
|
$authToken->client_id,
|
||||||
|
'Auth token revoked'
|
||||||
|
);
|
||||||
$authToken->delete();
|
$authToken->delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
app/Services/LogService.php
Normal file
22
app/Services/LogService.php
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Request;
|
||||||
|
|
||||||
|
class LogService
|
||||||
|
{
|
||||||
|
public function logOperation(string $userType, int $userId, string $operation): void
|
||||||
|
{
|
||||||
|
DB::table('operation_logs')->insert([
|
||||||
|
'user_type' => $userType,
|
||||||
|
'user_id' => $userId,
|
||||||
|
'operation' => $operation,
|
||||||
|
'ip_address' => Request::ip(),
|
||||||
|
'created_at' => now(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
80
database/sql/schema.sql
Normal file
80
database/sql/schema.sql
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
-- Create admins table
|
||||||
|
CREATE TABLE `admins` (
|
||||||
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` VARCHAR(50) NOT NULL,
|
||||||
|
`password` VARCHAR(255) NOT NULL,
|
||||||
|
`email` VARCHAR(100) NULL DEFAULT NULL,
|
||||||
|
`role` ENUM('super', 'admin') NOT NULL DEFAULT 'admin',
|
||||||
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `admins_username_unique` (`username`),
|
||||||
|
KEY `admins_email_index` (`email`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Create llm_providers table
|
||||||
|
CREATE TABLE `llm_providers` (
|
||||||
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` VARCHAR(100) NOT NULL,
|
||||||
|
`service_name` VARCHAR(100) NOT NULL,
|
||||||
|
`api_url` VARCHAR(255) NOT NULL,
|
||||||
|
`api_token` VARCHAR(255) NOT NULL,
|
||||||
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `llm_providers_name_unique` (`name`),
|
||||||
|
KEY `llm_providers_service_name_index` (`service_name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Create clients table
|
||||||
|
CREATE TABLE `clients` (
|
||||||
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` VARCHAR(100) NOT NULL,
|
||||||
|
`llm_provider_id` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `clients_llm_provider_id_foreign` (`llm_provider_id`),
|
||||||
|
CONSTRAINT `clients_llm_provider_id_foreign` FOREIGN KEY (`llm_provider_id`)
|
||||||
|
REFERENCES `llm_providers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Create auth_tokens table
|
||||||
|
CREATE TABLE `auth_tokens` (
|
||||||
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`client_id` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`token` CHAR(64) NOT NULL,
|
||||||
|
`expires_at` TIMESTAMP NULL DEFAULT NULL,
|
||||||
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `auth_tokens_token_unique` (`token`),
|
||||||
|
KEY `auth_tokens_client_id_index` (`client_id`),
|
||||||
|
CONSTRAINT `auth_tokens_client_id_foreign` FOREIGN KEY (`client_id`)
|
||||||
|
REFERENCES `clients` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Create admin_client table (pivot table)
|
||||||
|
CREATE TABLE `admin_client` (
|
||||||
|
`admin_id` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`client_id` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`assigned_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`admin_id`, `client_id`),
|
||||||
|
KEY `admin_client_client_id_foreign` (`client_id`),
|
||||||
|
CONSTRAINT `admin_client_admin_id_foreign` FOREIGN KEY (`admin_id`)
|
||||||
|
REFERENCES `admins` (`id`) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT `admin_client_client_id_foreign` FOREIGN KEY (`client_id`)
|
||||||
|
REFERENCES `clients` (`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
-- Create operation_logs table
|
||||||
|
CREATE TABLE `operation_logs` (
|
||||||
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_type` ENUM('admin', 'client') NOT NULL,
|
||||||
|
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||||
|
`operation` VARCHAR(255) NOT NULL,
|
||||||
|
`ip_address` VARCHAR(45) NULL DEFAULT NULL,
|
||||||
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `operation_logs_user_type_user_id_index` (`user_type`, `user_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
Loading…
Reference in a new issue