fix token issue
This commit is contained in:
parent
fdaccc918f
commit
ae4ef60215
5 changed files with 179 additions and 6 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use App\Constants\ErrorCode;
|
use App\Constants\ErrorCode;
|
||||||
|
use App\Models\Admin;
|
||||||
use Closure;
|
use Closure;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
@ -22,19 +23,56 @@ public function handle(Request $request, Closure $next): Response
|
||||||
], Response::HTTP_UNAUTHORIZED);
|
], Response::HTTP_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @var Admin $admin */
|
||||||
$admin = Auth::guard('admin')->user();
|
$admin = Auth::guard('admin')->user();
|
||||||
|
|
||||||
// 检查是否是管理员
|
// 检查是否是有效的管理员
|
||||||
if (!$admin || !in_array($admin->role, ['super', 'admin'])) {
|
if (!$admin->isValidAdmin()) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'error' => ErrorCode::FORBIDDEN,
|
'error' => ErrorCode::FORBIDDEN,
|
||||||
'message' => '无权访问管理员资源。',
|
'message' => '无权访问管理员资源。',
|
||||||
], Response::HTTP_FORBIDDEN);
|
], Response::HTTP_FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查资源访问权限
|
||||||
|
if (!$this->checkResourcePermission($request, $admin)) {
|
||||||
|
return response()->json([
|
||||||
|
'error' => ErrorCode::FORBIDDEN,
|
||||||
|
'message' => '无权访问该资源。',
|
||||||
|
], Response::HTTP_FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
// Add admin information to the request
|
// Add admin information to the request
|
||||||
$request->merge(['admin' => $admin]);
|
$request->merge(['admin' => $admin]);
|
||||||
|
|
||||||
return $next($request);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,20 @@
|
||||||
|
|
||||||
class Admin extends Authenticatable
|
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 $table = 'admins';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
|
@ -32,8 +46,56 @@ public function clients(): BelongsToMany
|
||||||
->withTimestamp('assigned_at');
|
->withTimestamp('assigned_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查是否是超级管理员
|
||||||
|
*/
|
||||||
public function isSuperAdmin(): bool
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,34 @@
|
||||||
|
|
||||||
class Client extends Model
|
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 $table = 'clients';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'name',
|
'name',
|
||||||
'llm_provider_id',
|
'llm_provider_id',
|
||||||
|
'rate_limit',
|
||||||
|
'timeout',
|
||||||
|
'status',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'rate_limit' => 'integer',
|
||||||
|
'timeout' => 'integer',
|
||||||
|
'status' => 'string',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function llmProvider(): BelongsTo
|
public function llmProvider(): BelongsTo
|
||||||
|
|
@ -26,11 +49,27 @@ public function llmProvider(): BelongsTo
|
||||||
public function admins(): BelongsToMany
|
public function admins(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Admin::class, 'admin_client')
|
return $this->belongsToMany(Admin::class, 'admin_client')
|
||||||
->withTimestamp('assigned_at');
|
->withTimestamps();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function authTokens(): HasMany
|
public function authTokens(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(AuthToken::class);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,20 @@
|
||||||
|
|
||||||
class LlmProvider extends Model
|
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 $table = 'llm_providers';
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
|
@ -16,14 +30,27 @@ class LlmProvider extends Model
|
||||||
'service_name',
|
'service_name',
|
||||||
'api_url',
|
'api_url',
|
||||||
'api_token',
|
'api_token',
|
||||||
|
'status',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $hidden = [
|
protected $hidden = [
|
||||||
'api_token',
|
'api_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'status' => 'string',
|
||||||
|
];
|
||||||
|
|
||||||
public function clients(): HasMany
|
public function clients(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Client::class);
|
return $this->hasMany(Client::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查提供商是否处于活跃状态
|
||||||
|
*/
|
||||||
|
public function isActive(): bool
|
||||||
|
{
|
||||||
|
return $this->status === self::STATUS_ACTIVE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,13 @@ CREATE TABLE `llm_providers` (
|
||||||
`service_name` VARCHAR(100) NOT NULL,
|
`service_name` VARCHAR(100) NOT NULL,
|
||||||
`api_url` VARCHAR(255) NOT NULL,
|
`api_url` VARCHAR(255) NOT NULL,
|
||||||
`api_token` 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,
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
UNIQUE KEY `llm_providers_name_unique` (`name`),
|
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;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
-- Create clients table
|
-- Create clients table
|
||||||
|
|
@ -31,10 +33,14 @@ CREATE TABLE `clients` (
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
`name` VARCHAR(100) NOT NULL,
|
`name` VARCHAR(100) NOT NULL,
|
||||||
`llm_provider_id` BIGINT UNSIGNED 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,
|
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `clients_llm_provider_id_foreign` (`llm_provider_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`)
|
CONSTRAINT `clients_llm_provider_id_foreign` FOREIGN KEY (`llm_provider_id`)
|
||||||
REFERENCES `llm_providers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
REFERENCES `llm_providers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
@ -58,7 +64,8 @@ CREATE TABLE `auth_tokens` (
|
||||||
CREATE TABLE `admin_client` (
|
CREATE TABLE `admin_client` (
|
||||||
`admin_id` BIGINT UNSIGNED NOT NULL,
|
`admin_id` BIGINT UNSIGNED NOT NULL,
|
||||||
`client_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`),
|
PRIMARY KEY (`admin_id`, `client_id`),
|
||||||
KEY `admin_client_client_id_foreign` (`client_id`),
|
KEY `admin_client_client_id_foreign` (`client_id`),
|
||||||
CONSTRAINT `admin_client_admin_id_foreign` FOREIGN KEY (`admin_id`)
|
CONSTRAINT `admin_client_admin_id_foreign` FOREIGN KEY (`admin_id`)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue