From c44c25d86f2db3bc490dc559f745cec290f20583 Mon Sep 17 00:00:00 2001 From: Jethro Lin Date: Wed, 4 Dec 2024 12:01:56 +0800 Subject: [PATCH] =?UTF-8?q?4.=20[API=20=E8=AF=A6=E7=BB=86=E8=AF=B4?= =?UTF-8?q?=E6=98=8E](#4-api-=E8=AF=A6=E7=BB=86=E8=AF=B4=E6=98=8E)=20=20?= =?UTF-8?q?=20=20-=20[4.1=20=E8=AE=A4=E8=AF=81=20API](#41-=E8=AE=A4?= =?UTF-8?q?=E8=AF=81-api)=20=20=20=20=20=20-=20[4.1.1=20=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=AE=BF=E9=97=AE=E4=BB=A4=E7=89=8C](#411-=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E8=AE=BF=E9=97=AE=E4=BB=A4=E7=89=8C)=20=20=20=20-=20[4.2=20?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=94=A8=E6=88=B7=20API](#42-=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=94=A8=E6=88=B7-api)=20=20=20=20=20=20-=20[4.2.1=20?= =?UTF-8?q?=E5=8F=91=E9=80=81=E6=8F=90=E7=A4=BA=E8=AF=8D=E8=AF=B7=E6=B1=82?= =?UTF-8?q?](#421-=E5=8F=91=E9=80=81=E6=8F=90=E7=A4=BA=E8=AF=8D=E8=AF=B7?= =?UTF-8?q?=E6=B1=82)=20=20=20=20-=20[4.3=20=E7=AE=A1=E7=90=86=E5=91=98=20?= =?UTF-8?q?API](#43-=E7=AE=A1=E7=90=86=E5=91=98-api)=20=20=20=20=20=20-=20?= =?UTF-8?q?[4.3.1=20LLM=20=E6=8F=90=E4=BE=9B=E5=95=86=E7=AE=A1=E7=90=86](#?= =?UTF-8?q?431-llm-=E6=8F=90=E4=BE=9B=E5=95=86=E7=AE=A1=E7=90=86)=20=20=20?= =?UTF-8?q?=20=20=20=20=20-=20[4.3.1.1=20=E6=96=B0=E5=A2=9E=20LLM=20?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E5=95=86](#4311-=E6=96=B0=E5=A2=9E-llm-?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E5=95=86)=20=20=20=20=20=20=20=20-=20[4.3.1.?= =?UTF-8?q?2=20=E4=BF=AE=E6=94=B9=20LLM=20=E6=8F=90=E4=BE=9B=E5=95=86](#43?= =?UTF-8?q?12-=E4=BF=AE=E6=94=B9-llm-=E6=8F=90=E4=BE=9B=E5=95=86)=20=20=20?= =?UTF-8?q?=20=20=20=20=20-=20[4.3.1.3=20=E5=88=A0=E9=99=A4=20LLM=20?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E5=95=86](#4313-=E5=88=A0=E9=99=A4-llm-?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E5=95=86)=20=20=20=20=20=20=20=20-=20[4.3.1.?= =?UTF-8?q?4=20=E8=8E=B7=E5=8F=96=20LLM=20=E6=8F=90=E4=BE=9B=E5=95=86?= =?UTF-8?q?=E5=88=97=E8=A1=A8](#4314-=E8=8E=B7=E5=8F=96-llm-=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E5=95=86=E5=88=97=E8=A1=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Api/Admin/AuthController.php | 144 +++++++- .../Api/Admin/ClientController.php | 203 ++++++++++- .../Api/Admin/LlmProviderController.php | 324 +++++++++++++++++- app/Http/Controllers/Api/AuthController.php | 38 +- app/Http/Controllers/Api/LlmController.php | 150 +++++++- app/Http/Middleware/AdminAuthenticate.php | 31 +- app/Providers/AppServiceProvider.php | 2 + app/Rules/ThrottleAuthToken.php | 28 ++ routes/api.php | 23 +- 9 files changed, 933 insertions(+), 10 deletions(-) create mode 100644 app/Rules/ThrottleAuthToken.php diff --git a/app/Http/Controllers/Api/Admin/AuthController.php b/app/Http/Controllers/Api/Admin/AuthController.php index 0519ecb..e649197 100644 --- a/app/Http/Controllers/Api/Admin/AuthController.php +++ b/app/Http/Controllers/Api/Admin/AuthController.php @@ -1 +1,143 @@ - \ No newline at end of file +validate([ + 'username' => 'required|string', + 'password' => 'required|string', + ]); + + if (!Auth::guard('admin')->attempt($validated)) { + return response()->json([ + 'error' => 'invalid_credentials', + 'message' => '用户名或密码错误。', + ], 401); + } + + /** @var Admin $admin */ + $admin = Auth::guard('admin')->user(); + + $this->logService->logOperation( + 'admin', + $admin->id, + 'Admin logged in' + ); + + return response()->json([ + 'id' => $admin->id, + 'username' => $admin->username, + 'email' => $admin->email, + 'role' => $admin->role, + ]); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (\Exception $e) { + Log::error('Error during admin login', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + public function logout(Request $request): JsonResponse + { + /** @var Admin $admin */ + $admin = Auth::guard('admin')->user(); + + Auth::guard('admin')->logout(); + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + $this->logService->logOperation( + 'admin', + $admin->id, + 'Admin logged out' + ); + + return response()->json([ + 'message' => '已成功退出登录。', + ]); + } + + public function changePassword(Request $request): JsonResponse + { + try { + $validated = $request->validate([ + 'current_password' => 'required|string', + 'new_password' => 'required|string|min:8|confirmed', + ]); + + /** @var Admin $admin */ + $admin = Auth::guard('admin')->user(); + + if (!Hash::check($validated['current_password'], $admin->password)) { + return response()->json([ + 'error' => 'invalid_password', + 'message' => '当前密码错误。', + ], 422); + } + + $admin->update([ + 'password' => Hash::make($validated['new_password']), + ]); + + $this->logService->logOperation( + 'admin', + $admin->id, + 'Changed password' + ); + + return response()->json([ + 'message' => '密码已成功修改。', + ]); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (\Exception $e) { + Log::error('Error changing admin password', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } +} diff --git a/app/Http/Controllers/Api/Admin/ClientController.php b/app/Http/Controllers/Api/Admin/ClientController.php index 0519ecb..8a0f5a1 100644 --- a/app/Http/Controllers/Api/Admin/ClientController.php +++ b/app/Http/Controllers/Api/Admin/ClientController.php @@ -1 +1,202 @@ - \ No newline at end of file +admin; + $query = $admin->isSuperAdmin() ? Client::query() : $admin->clients(); + + $clients = $query->with('llmProvider')->get(); + return response()->json($clients); + } + + public function store(Request $request): JsonResponse + { + try { + $validated = $request->validate([ + 'name' => 'required|string|max:100', + 'llm_provider_id' => 'required|exists:llm_providers,id', + ]); + + DB::beginTransaction(); + + $client = Client::create($validated); + + // Associate client with admin + $request->admin->clients()->attach($client->id); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Created client: {$client->name}" + ); + + DB::commit(); + return response()->json($client, 201); + + } catch (ValidationException $e) { + DB::rollBack(); + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (\Exception $e) { + DB::rollBack(); + Log::error('Error creating client', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + public function update(Request $request, int $id): JsonResponse + { + try { + $client = $this->getAuthorizedClient($request->admin, $id); + + $validated = $request->validate([ + 'name' => 'required|string|max:100', + 'llm_provider_id' => 'required|exists:llm_providers,id', + ]); + + $client->update($validated); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Updated client: {$client->name}" + ); + + return response()->json($client); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (\Exception $e) { + Log::error('Error updating client', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + public function destroy(Request $request, int $id): JsonResponse + { + try { + $client = $this->getAuthorizedClient($request->admin, $id); + + $clientName = $client->name; + $client->delete(); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Deleted client: {$clientName}" + ); + + return response()->json([ + 'message' => '客户用户已删除。', + ]); + + } catch (\Exception $e) { + Log::error('Error deleting client', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + public function generateAuthToken(Request $request, int $id): JsonResponse + { + try { + $client = $this->getAuthorizedClient($request->admin, $id); + + $validated = $request->validate([ + 'expires_in_days' => 'nullable|integer|min:1', + ]); + + $token = $this->tokenService->generateAuthToken( + $client, + $validated['expires_in_days'] ?? null + ); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Generated auth token for client: {$client->name}" + ); + + return response()->json([ + 'client_id' => $client->id, + 'auth_token' => $token->token, + 'created_at' => $token->created_at, + 'expires_at' => $token->expires_at, + ]); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (\Exception $e) { + Log::error('Error generating auth token', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + private function getAuthorizedClient($admin, int $id): Client + { + $query = $admin->isSuperAdmin() ? Client::query() : $admin->clients(); + + $client = $query->findOrFail($id); + + return $client; + } +} diff --git a/app/Http/Controllers/Api/Admin/LlmProviderController.php b/app/Http/Controllers/Api/Admin/LlmProviderController.php index 0519ecb..ac8b8ca 100644 --- a/app/Http/Controllers/Api/Admin/LlmProviderController.php +++ b/app/Http/Controllers/Api/Admin/LlmProviderController.php @@ -1 +1,323 @@ - \ No newline at end of file +input('per_page', 15); + $perPage = min(max($perPage, 1), 100); // 限制每页数量在 1-100 之间 + + $providers = LlmProvider::orderBy('created_at', 'desc') + ->paginate($perPage); + + return response()->json([ + 'data' => $providers->items(), + 'meta' => [ + 'current_page' => $providers->currentPage(), + 'per_page' => $providers->perPage(), + 'total' => $providers->total(), + 'total_pages' => $providers->lastPage(), + ], + ]); + + } catch (\Exception $e) { + Log::error('Error fetching LLM providers', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + /** + * Create new LLM provider + * + * @param Request $request + * @return JsonResponse + * + * Request body: + * { + * "name": "string", + * "service_name": "string", + * "api_url": "string", + * "api_token": "string" + * } + * + * Success response (201): + * { + * "id": 1001, + * "name": "OpenAI", + * "service_name": "openai", + * "api_url": "https://api.openai.com/v1/chat/completions", + * "created_at": "2023-10-01T14:00:00Z" + * } + * + * Error response (422): + * { + * "error": "validation_error", + * "message": "请求参数验证失败。", + * "errors": { + * "name": ["提供商名称已存在。"], + * "api_url": ["API URL 格式不正确。"] + * } + * } + */ + public function store(Request $request): JsonResponse + { + try { + $validated = $request->validate([ + 'name' => [ + 'required', + 'string', + 'max:100', + 'unique:llm_providers', + 'regex:/^[\w\-\s]+$/u', // 只允许字母、数字、下划线、横线和空格 + ], + 'service_name' => [ + 'required', + 'string', + 'max:100', + 'regex:/^[\w\-]+$/u', // 只允许字母、数字、下划线和横线 + ], + 'api_url' => [ + 'required', + 'string', + 'max:255', + 'url', + 'starts_with:https', // 强制使用 HTTPS + ], + 'api_token' => 'required|string|max:255', + ], [ + 'name.regex' => '提供商名称只能包含字母、数字、下划线、横线和空��。', + 'service_name.regex' => '服务名称只能包含字母、数字、下划线和横线。', + 'api_url.starts_with' => 'API URL 必须使用 HTTPS 协议。', + ]); + + $provider = LlmProvider::create($validated); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Created LLM provider: {$provider->name}" + ); + + return response()->json($provider, 201); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (\Exception $e) { + Log::error('Error creating LLM provider', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + /** + * Update LLM provider + * + * @param Request $request + * @param int $id + * @return JsonResponse + * + * Request body: + * { + * "name": "string", + * "service_name": "string", + * "api_url": "string", + * "api_token": "string" + * } + * + * Success response: + * { + * "id": 1001, + * "name": "OpenAI Updated", + * "service_name": "openai", + * "api_url": "https://api.openai.com/v1/chat/completions", + * "updated_at": "2023-10-02T14:00:00Z" + * } + */ + public function update(Request $request, int $id): JsonResponse + { + try { + $provider = LlmProvider::findOrFail($id); + + $validated = $request->validate([ + 'name' => [ + 'required', + 'string', + 'max:100', + "unique:llm_providers,name,{$id}", + 'regex:/^[\w\-\s]+$/u', // 只允许字母、数字、下划线、横线和空格 + ], + 'service_name' => [ + 'required', + 'string', + 'max:100', + 'regex:/^[\w\-]+$/u', // 只允许字母、数字、下划线和横线 + ], + 'api_url' => [ + 'required', + 'string', + 'max:255', + 'url', + 'starts_with:https', // 强制使用 HTTPS + ], + 'api_token' => 'required|string|max:255', + ], [ + 'name.regex' => '提供商名称只能包含字母、数字、下划线、横线和空格。', + 'service_name.regex' => '服务名称只能包含字母、数字、下划线和横线。', + 'api_url.starts_with' => 'API URL 必须使用 HTTPS 协议。', + ]); + + $provider->update($validated); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Updated LLM provider: {$provider->name}" + ); + + return response()->json($provider); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'errors' => $e->errors(), + ], 422); + } catch (ModelNotFoundException $e) { + return response()->json([ + 'error' => 'not_found', + 'message' => 'LLM 提供商不存在。', + ], 404); + } catch (\Exception $e) { + Log::error('Error updating LLM provider', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } + + /** + * Delete LLM provider + * + * @param Request $request + * @param int $id + * @return JsonResponse + * + * Success response: + * { + * "message": "提供商已删除。" + * } + */ + public function destroy(Request $request, int $id): JsonResponse + { + try { + $provider = LlmProvider::findOrFail($id); + + // 检查是否有客户正在使用该提供商 + if ($provider->clients()->exists()) { + return response()->json([ + 'error' => 'provider_in_use', + 'message' => '该提供商正在被客户使用,无法删除。', + ], 422); + } + + $providerName = $provider->name; + $provider->delete(); + + $this->logService->logOperation( + 'admin', + $request->admin->id, + "Deleted LLM provider: {$providerName}" + ); + + return response()->json([ + 'message' => '提供商已删除。', + ]); + + } catch (ModelNotFoundException $e) { + return response()->json([ + 'error' => 'not_found', + 'message' => 'LLM 提供商不存在。', + ], 404); + } catch (\Exception $e) { + Log::error('Error deleting LLM provider', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + 'provider_id' => $id, + ]); + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } +} diff --git a/app/Http/Controllers/Api/AuthController.php b/app/Http/Controllers/Api/AuthController.php index ed03656..70f3701 100644 --- a/app/Http/Controllers/Api/AuthController.php +++ b/app/Http/Controllers/Api/AuthController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; +use App\Rules\ThrottleAuthToken; use App\Services\Auth\TokenService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -17,11 +18,39 @@ public function __construct( private readonly TokenService $tokenService ) {} + /** + * Get access token using auth token + * + * @param Request $request + * @return JsonResponse + * + * Request body: + * { + * "auth_token": "string" + * } + * + * Success response: + * { + * "access_token": "string", + * "expires_in": 3600 + * } + * + * Error response: + * { + * "error": "error_code", + * "message": "错误描述" + * } + */ public function getAccessToken(Request $request): JsonResponse { try { $validated = $request->validate([ - 'auth_token' => 'required|string', + 'auth_token' => [ + 'required', + 'string', + 'size:64', + new ThrottleAuthToken, + ], ]); $authToken = $this->tokenService->validateAuthToken($validated['auth_token']); @@ -33,14 +62,15 @@ public function getAccessToken(Request $request): JsonResponse ], 401); } - $accessToken = $this->tokenService->generateAccessToken($authToken); + $result = $this->tokenService->generateAccessToken($authToken); - return response()->json($accessToken); + return response()->json($result); } catch (ValidationException $e) { return response()->json([ 'error' => 'invalid_request', - 'message' => '请求参数缺失。', + 'message' => '请求参数缺失或格式错误。', + 'details' => $e->errors(), ], 400); } catch (\Exception $e) { Log::error('Error generating access token', [ diff --git a/app/Http/Controllers/Api/LlmController.php b/app/Http/Controllers/Api/LlmController.php index 0519ecb..e437888 100644 --- a/app/Http/Controllers/Api/LlmController.php +++ b/app/Http/Controllers/Api/LlmController.php @@ -1 +1,149 @@ - \ No newline at end of file +get('client_id'); + + // 检查请求频率限制 + $key = 'llm_request_' . $clientId; + if (RateLimiter::tooManyAttempts($key, self::MAX_ATTEMPTS)) { + $seconds = RateLimiter::availableIn($key); + return response()->json([ + 'error' => 'too_many_requests', + 'message' => "请求过于频繁,请在 {$seconds} 秒后重试。", + ], 429); + } + + $validated = $request->validate([ + 'prompt' => 'required|string|max:4096', + ]); + + $client = Client::with('llmProvider')->findOrFail($clientId); + $provider = $client->llmProvider; + + // Send request to LLM provider with timeout + $response = Http::timeout(self::REQUEST_TIMEOUT) + ->withToken($provider->api_token) + ->withHeaders([ + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + ]) + ->post($provider->api_url, [ + 'prompt' => $validated['prompt'], + ]); + + if (!$response->successful()) { + Log::error('LLM provider request failed', [ + 'status' => $response->status(), + 'body' => $response->body(), + 'provider' => $provider->name, + ]); + + throw new \Exception('LLM provider request failed: ' . $response->body()); + } + + // 记录成功的请求 + RateLimiter::hit($key, self::DECAY_MINUTES * 60); + + $this->logService->logOperation( + 'client', + $client->id, + 'Sent prompt to LLM provider: ' . $provider->name + ); + + return response()->json([ + 'response' => $response->json(), + ]); + + } catch (ValidationException $e) { + return response()->json([ + 'error' => 'validation_error', + 'message' => '请求参数验证失败。', + 'details' => $e->errors(), + ], 422); + } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) { + return response()->json([ + 'error' => 'not_found', + 'message' => '客户用户不存在。', + ], 404); + } catch (\Illuminate\Http\Client\ConnectionException $e) { + Log::error('LLM provider connection timeout', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + return response()->json([ + 'error' => 'provider_timeout', + 'message' => 'LLM 提供商响应超时,请稍后重试。', + ], 504); + } catch (\Exception $e) { + Log::error('Error processing LLM request', [ + 'error' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + + if (str_contains($e->getMessage(), 'LLM provider request failed')) { + return response()->json([ + 'error' => 'provider_error', + 'message' => 'LLM 提供商服务异常,请稍后重试。', + ], 502); + } + + return response()->json([ + 'error' => 'server_error', + 'message' => '服务器内部错误。', + ], 500); + } + } +} diff --git a/app/Http/Middleware/AdminAuthenticate.php b/app/Http/Middleware/AdminAuthenticate.php index 0519ecb..413fa44 100644 --- a/app/Http/Middleware/AdminAuthenticate.php +++ b/app/Http/Middleware/AdminAuthenticate.php @@ -1 +1,30 @@ - \ No newline at end of file +check()) { + return response()->json([ + 'error' => 'unauthorized', + 'message' => '未授权,请先登录。', + ], 401); + } + + $admin = Auth::guard('admin')->user(); + + // Add admin information to the request + $request->merge(['admin' => $admin]); + + return $next($request); + } +} diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 479a6ab..7cc4e8f 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Http\Middleware\AdminAuthenticate; use App\Http\Middleware\ValidateAccessToken; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Facades\Route; @@ -22,5 +23,6 @@ public function register(): void public function boot(): void { Route::aliasMiddleware('auth.access_token', ValidateAccessToken::class); + Route::aliasMiddleware('auth.admin', AdminAuthenticate::class); } } diff --git a/app/Rules/ThrottleAuthToken.php b/app/Rules/ThrottleAuthToken.php new file mode 100644 index 0000000..3dc27b9 --- /dev/null +++ b/app/Rules/ThrottleAuthToken.php @@ -0,0 +1,28 @@ +group(function () { - // Add protected routes here + Route::post('/llm/request', [LlmController::class, 'request']); +}); + +// Admin authentication routes +Route::prefix('admin')->group(function () { + Route::post('login', [AdminAuthController::class, 'login']); + + Route::middleware('auth.admin')->group(function () { + Route::post('logout', [AdminAuthController::class, 'logout']); + Route::post('change-password', [AdminAuthController::class, 'changePassword']); + + // LLM Provider management + Route::apiResource('llm-providers', LlmProviderController::class); + + // Client management + Route::apiResource('clients', ClientController::class); + Route::post('clients/{id}/auth-token', [ClientController::class, 'generateAuthToken']); + }); });