fix token issue

This commit is contained in:
Jethro Lin 2024-12-04 12:54:46 +08:00
parent fdaccc918f
commit ae4ef60215
5 changed files with 179 additions and 6 deletions

View file

@ -5,6 +5,7 @@
namespace App\Http\Middleware;
use App\Constants\ErrorCode;
use App\Models\Admin;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@ -22,19 +23,56 @@ public function handle(Request $request, Closure $next): Response
], Response::HTTP_UNAUTHORIZED);
}
/** @var Admin $admin */
$admin = Auth::guard('admin')->user();
// 检查是否是管理员
if (!$admin || !in_array($admin->role, ['super', 'admin'])) {
// 检查是否是有效的管理员
if (!$admin->isValidAdmin()) {
return response()->json([
'error' => ErrorCode::FORBIDDEN,
'message' => '无权访问管理员资源。',
], Response::HTTP_FORBIDDEN);
}
// 检查资源访问权限
if (!$this->checkResourcePermission($request, $admin)) {
return response()->json([
'error' => ErrorCode::FORBIDDEN,
'message' => '无权访问该资源。',
], Response::HTTP_FORBIDDEN);
}
// Add admin information to the request
$request->merge(['admin' => $admin]);
return $next($request);
}
/**
* 检查管理员是否有权限访问请求的资源
*/
private function checkResourcePermission(Request $request, Admin $admin): bool
{
// 超级管理员可以访问所有资源
if ($admin->isSuperAdmin()) {
return true;
}
// 获取路由参数
$clientId = $request->route('client') ?? $request->route('id');
$providerId = $request->route('llm_provider') ?? $request->route('id');
// 检查客户管理权限
if ($clientId && str_contains($request->path(), 'clients')) {
return $admin->canManageClient((int)$clientId);
}
// 检查LLM提供商管理权限
if ($providerId && str_contains($request->path(), 'llm-providers')) {
return $admin->canManageLlmProvider((int)$providerId);
}
// 默认允许访问其他资源
return true;
}
}

View file

@ -9,6 +9,20 @@
class Admin extends Authenticatable
{
/**
* 管理员角色常量
*/
public const ROLE_SUPER = 'super';
public const ROLE_ADMIN = 'admin';
/**
* 有效的角色列表
*/
public const VALID_ROLES = [
self::ROLE_SUPER,
self::ROLE_ADMIN,
];
protected $table = 'admins';
protected $fillable = [
@ -32,8 +46,56 @@ public function clients(): BelongsToMany
->withTimestamp('assigned_at');
}
/**
* 检查是否是超级管理员
*/
public function isSuperAdmin(): bool
{
return $this->role === 'super';
return $this->role === self::ROLE_SUPER;
}
/**
* 检查是否是普通管理员
*/
public function isAdmin(): bool
{
return $this->role === self::ROLE_ADMIN;
}
/**
* 检查是否有效的管理员(包括超级管理员和普通管理员)
*/
public function isValidAdmin(): bool
{
return in_array($this->role, self::VALID_ROLES, true);
}
/**
* 检查是否可以管理指定的客户
*/
public function canManageClient(int $clientId): bool
{
if ($this->isSuperAdmin()) {
return true;
}
return $this->clients()->where('client_id', $clientId)->exists();
}
/**
* 检查是否可以管理指定的LLM提供商
*/
public function canManageLlmProvider(int $providerId): bool
{
if ($this->isSuperAdmin()) {
return true;
}
// 普通管理员只能管理与其关联客户绑定的LLM提供商
return $this->clients()
->whereHas('llmProvider', function ($query) use ($providerId) {
$query->where('id', $providerId);
})
->exists();
}
}

View file

@ -11,11 +11,34 @@
class Client extends Model
{
/**
* 客户状态常量
*/
public const STATUS_ACTIVE = 'active';
public const STATUS_INACTIVE = 'inactive';
/**
* 有效的状态列表
*/
public const VALID_STATUSES = [
self::STATUS_ACTIVE,
self::STATUS_INACTIVE,
];
protected $table = 'clients';
protected $fillable = [
'name',
'llm_provider_id',
'rate_limit',
'timeout',
'status',
];
protected $casts = [
'rate_limit' => 'integer',
'timeout' => 'integer',
'status' => 'string',
];
public function llmProvider(): BelongsTo
@ -26,11 +49,27 @@ public function llmProvider(): BelongsTo
public function admins(): BelongsToMany
{
return $this->belongsToMany(Admin::class, 'admin_client')
->withTimestamp('assigned_at');
->withTimestamps();
}
public function authTokens(): HasMany
{
return $this->hasMany(AuthToken::class);
}
/**
* 检查客户是否处于活跃状态
*/
public function isActive(): bool
{
return $this->status === self::STATUS_ACTIVE;
}
/**
* 检查是否可以发送LLM请求
*/
public function canSendLlmRequest(): bool
{
return $this->isActive() && $this->llmProvider->isActive();
}
}

View file

@ -9,6 +9,20 @@
class LlmProvider extends Model
{
/**
* 提供商状态常量
*/
public const STATUS_ACTIVE = 'active';
public const STATUS_INACTIVE = 'inactive';
/**
* 有效的状态列表
*/
public const VALID_STATUSES = [
self::STATUS_ACTIVE,
self::STATUS_INACTIVE,
];
protected $table = 'llm_providers';
protected $fillable = [
@ -16,14 +30,27 @@ class LlmProvider extends Model
'service_name',
'api_url',
'api_token',
'status',
];
protected $hidden = [
'api_token',
];
protected $casts = [
'status' => 'string',
];
public function clients(): HasMany
{
return $this->hasMany(Client::class);
}
/**
* 检查提供商是否处于活跃状态
*/
public function isActive(): bool
{
return $this->status === self::STATUS_ACTIVE;
}
}

View file

@ -19,11 +19,13 @@ CREATE TABLE `llm_providers` (
`service_name` VARCHAR(100) NOT NULL,
`api_url` VARCHAR(255) NOT NULL,
`api_token` VARCHAR(255) NOT NULL,
`status` ENUM('active', 'inactive') NOT NULL DEFAULT 'active',
`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`)
KEY `llm_providers_service_name_index` (`service_name`),
KEY `llm_providers_status_index` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Create clients table
@ -31,10 +33,14 @@ CREATE TABLE `clients` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`llm_provider_id` BIGINT UNSIGNED NOT NULL,
`rate_limit` INT NOT NULL DEFAULT 60,
`timeout` INT NOT NULL DEFAULT 30,
`status` ENUM('active', 'inactive') NOT NULL DEFAULT 'active',
`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`),
KEY `clients_status_index` (`status`),
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;
@ -58,7 +64,8 @@ CREATE TABLE `auth_tokens` (
CREATE TABLE `admin_client` (
`admin_id` BIGINT UNSIGNED NOT NULL,
`client_id` BIGINT UNSIGNED NOT NULL,
`assigned_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE 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`)