| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- <?php
- namespace App\Module\OpenAPI\Services;
- use App\Module\OpenAPI\Models\OpenApiApp;
- use App\Module\OpenAPI\Enums\APP_STATUS;
- use App\Module\OpenAPI\Enums\AUTH_TYPE;
- use App\Module\OpenAPI\Enums\SCOPE_TYPE;
- use App\Module\OpenAPI\Events\AppCreatedEvent;
- use Illuminate\Support\Facades\Cache;
- use Illuminate\Support\Facades\Event;
- use Illuminate\Support\Facades\Hash;
- /**
- * OpenAPI核心服务
- */
- class OpenApiService
- {
- /**
- * 创建新应用
- *
- * @param array $data
- * @return OpenApiApp
- */
- public function createApp(array $data): OpenApiApp
- {
- // 验证必填字段
- $this->validateRequiredFields($data);
- // 生成应用ID和密钥
- $data['app_id'] = OpenApiApp::generateAppId();
- $data['app_secret'] = OpenApiApp::generateAppSecret();
- // 设置默认值
- $data['status'] = $data['status'] ?? config('openapi.app.default_status', APP_STATUS::PENDING->value);
- $data['auth_type'] = $data['auth_type'] ?? config('openapi.auth.default_type', AUTH_TYPE::API_KEY->value);
- $data['scopes'] = $data['scopes'] ?? config('openapi.scopes.default', []);
- // 设置过期时间
- if (!isset($data['expires_at'])) {
- $expireDays = config('openapi.app.expire_days', 365);
- $data['expires_at'] = now()->addDays($expireDays);
- }
- // 加密应用密钥
- if (config('openapi.security.encrypt_secrets', true)) {
- $data['app_secret'] = encrypt($data['app_secret']);
- }
- // 创建应用
- $app = OpenApiApp::create($data);
- // 触发应用创建事件
- Event::dispatch(new AppCreatedEvent($app));
- return $app;
- }
- /**
- * 验证必填字段
- *
- * @param array $data
- * @throws \InvalidArgumentException
- */
- protected function validateRequiredFields(array $data): void
- {
- $requiredFields = config('openapi.app.required_fields', ['name', 'description', 'callback_url']);
- foreach ($requiredFields as $field) {
- if (empty($data[$field])) {
- throw new \InvalidArgumentException("字段 {$field} 是必填的");
- }
- }
- }
- /**
- * 审核应用
- *
- * @param int $appId
- * @param bool $approved
- * @param string $note
- * @param int $approvedBy
- * @return OpenApiApp
- */
- public function approveApp(int $appId, bool $approved, string $note = '', int $approvedBy = null): OpenApiApp
- {
- $app = OpenApiApp::findOrFail($appId);
- if ($app->status !== APP_STATUS::PENDING->value) {
- throw new \InvalidArgumentException('只能审核待审核状态的应用');
- }
- $app->update([
- 'status' => $approved ? APP_STATUS::APPROVED->value : APP_STATUS::REJECTED->value,
- 'approved_at' => now(),
- 'approved_by' => $approvedBy,
- 'approved_note' => $note,
- ]);
- // 清除缓存
- $this->clearAppCache($app->app_id);
- return $app;
- }
- /**
- * 激活应用
- *
- * @param int $appId
- * @return OpenApiApp
- */
- public function activateApp(int $appId): OpenApiApp
- {
- $app = OpenApiApp::findOrFail($appId);
- if (!in_array($app->status, [APP_STATUS::APPROVED->value, APP_STATUS::SUSPENDED->value])) {
- throw new \InvalidArgumentException('只能激活已审核或已暂停的应用');
- }
- $app->update(['status' => APP_STATUS::ACTIVE->value]);
- // 清除缓存
- $this->clearAppCache($app->app_id);
- return $app;
- }
- /**
- * 暂停应用
- *
- * @param int $appId
- * @param string $reason
- * @return OpenApiApp
- */
- public function suspendApp(int $appId, string $reason = ''): OpenApiApp
- {
- $app = OpenApiApp::findOrFail($appId);
- if ($app->status !== APP_STATUS::ACTIVE->value) {
- throw new \InvalidArgumentException('只能暂停激活状态的应用');
- }
- $app->update([
- 'status' => APP_STATUS::SUSPENDED->value,
- 'approved_note' => $reason,
- ]);
- // 清除缓存
- $this->clearAppCache($app->app_id);
- return $app;
- }
- /**
- * 禁用应用
- *
- * @param int $appId
- * @param string $reason
- * @return OpenApiApp
- */
- public function disableApp(int $appId, string $reason = ''): OpenApiApp
- {
- $app = OpenApiApp::findOrFail($appId);
- $app->update([
- 'status' => APP_STATUS::DISABLED->value,
- 'approved_note' => $reason,
- ]);
- // 清除缓存
- $this->clearAppCache($app->app_id);
- return $app;
- }
- /**
- * 重新生成应用密钥
- *
- * @param int $appId
- * @return OpenApiApp
- */
- public function regenerateSecret(int $appId): OpenApiApp
- {
- $app = OpenApiApp::findOrFail($appId);
- if (!config('openapi.api_key.allow_regenerate', true)) {
- throw new \InvalidArgumentException('不允许重新生成密钥');
- }
- $newSecret = OpenApiApp::generateAppSecret();
- // 加密应用密钥
- if (config('openapi.security.encrypt_secrets', true)) {
- $newSecret = encrypt($newSecret);
- }
- $app->update(['app_secret' => $newSecret]);
- // 清除缓存
- $this->clearAppCache($app->app_id);
- return $app;
- }
- /**
- * 更新应用权限
- *
- * @param int $appId
- * @param array $scopes
- * @return OpenApiApp
- */
- public function updateScopes(int $appId, array $scopes): OpenApiApp
- {
- $app = OpenApiApp::findOrFail($appId);
- // 验证权限范围
- $this->validateScopes($scopes);
- $app->update(['scopes' => $scopes]);
- // 清除缓存
- $this->clearAppCache($app->app_id);
- return $app;
- }
- /**
- * 验证权限范围
- *
- * @param array $scopes
- * @throws \InvalidArgumentException
- */
- protected function validateScopes(array $scopes): void
- {
- $validScopes = array_column(SCOPE_TYPE::cases(), 'value');
- $validScopes[] = '*'; // 允许通配符
- foreach ($scopes as $scope) {
- if (!in_array($scope, $validScopes)) {
- throw new \InvalidArgumentException("无效的权限范围: {$scope}");
- }
- }
- }
- /**
- * 通过应用ID获取应用信息
- *
- * @param string $appId
- * @return OpenApiApp|null
- */
- public function getAppByAppId(string $appId): ?OpenApiApp
- {
- $cacheKey = config('openapi.cache.keys.app_info');
- $cacheKey = str_replace('{app_id}', $appId, $cacheKey);
- return Cache::remember($cacheKey, config('openapi.cache.default_ttl', 300), function () use ($appId) {
- return OpenApiApp::where('app_id', $appId)->first();
- });
- }
- /**
- * 验证应用认证
- *
- * @param string $appId
- * @param string $appSecret
- * @return OpenApiApp|null
- */
- public function validateApp(string $appId, string $appSecret): ?OpenApiApp
- {
- $app = $this->getAppByAppId($appId);
- if (!$app) {
- return null;
- }
- // 检查应用状态
- if (!$app->can_call_api) {
- return null;
- }
- // 检查应用是否过期
- if ($app->is_expired) {
- return null;
- }
- // 验证密钥
- $storedSecret = $app->app_secret;
- if (config('openapi.security.encrypt_secrets', true)) {
- $storedSecret = decrypt($storedSecret);
- }
- if (!hash_equals($storedSecret, $appSecret)) {
- return null;
- }
- return $app;
- }
- /**
- * 检查应用权限
- *
- * @param OpenApiApp $app
- * @param string $scope
- * @return bool
- */
- public function checkScope(OpenApiApp $app, string $scope): bool
- {
- return $app->hasScope($scope);
- }
- /**
- * 检查IP白名单
- *
- * @param OpenApiApp $app
- * @param string $ip
- * @return bool
- */
- public function checkIpWhitelist(OpenApiApp $app, string $ip): bool
- {
- return $app->isIpAllowed($ip);
- }
- /**
- * 更新应用最后使用时间
- *
- * @param OpenApiApp $app
- * @return void
- */
- public function updateLastUsed(OpenApiApp $app): void
- {
- $app->updateLastUsed();
- }
- /**
- * 获取应用统计信息
- *
- * @param int $appId
- * @param int $days
- * @return array
- */
- public function getAppStats(int $appId, int $days = 30): array
- {
- // 这里可以实现统计逻辑
- // 暂时返回模拟数据
- return [
- 'total_requests' => 0,
- 'successful_requests' => 0,
- 'failed_requests' => 0,
- 'average_response_time' => 0,
- 'last_request_at' => null,
- ];
- }
- /**
- * 清除应用缓存
- *
- * @param string $appId
- * @return void
- */
- protected function clearAppCache(string $appId): void
- {
- $cacheKey = config('openapi.cache.keys.app_info');
- $cacheKey = str_replace('{app_id}', $appId, $cacheKey);
- Cache::forget($cacheKey);
- }
- /**
- * 批量处理过期应用
- *
- * @return int
- */
- public function handleExpiredApps(): int
- {
- $expiredApps = OpenApiApp::where('expires_at', '<', now())
- ->where('status', '!=', APP_STATUS::EXPIRED->value)
- ->get();
- $count = 0;
- foreach ($expiredApps as $app) {
- $app->update(['status' => APP_STATUS::EXPIRED->value]);
- $this->clearAppCache($app->app_id);
- $count++;
- }
- return $count;
- }
- /**
- * 获取用户的应用列表
- *
- * @param int $userId
- * @return \Illuminate\Database\Eloquent\Collection
- */
- public function getUserApps(int $userId)
- {
- return OpenApiApp::byUser($userId)->orderBy('created_at', 'desc')->get();
- }
- /**
- * 检查用户是否可以创建更多应用
- *
- * @param int $userId
- * @return bool
- */
- public function canCreateMoreApps(int $userId): bool
- {
- $maxApps = config('openapi.app.max_apps_per_user', 10);
- $currentCount = OpenApiApp::byUser($userId)->count();
- return $currentCount < $maxApps;
- }
- }
|