'integer', 'credentials' => 'array', 'is_active' => 'boolean', 'expires_at' => 'datetime', 'last_used_at' => 'datetime', 'usage_count' => 'integer', 'created_at' => 'datetime', 'updated_at' => 'datetime', ]; /** * 隐藏的属性 * * @var array */ protected $hidden = [ 'credentials', ]; /** * 获取认证类型枚举 * * @return AUTH_TYPE */ public function getAuthTypeEnum(): AUTH_TYPE { return AUTH_TYPE::from($this->type); } /** * 获取认证类型标签 * * @return string */ public function getTypeLabel(): string { return $this->getAuthTypeEnum()->getLabel(); } /** * 检查凭证是否已过期 * * @return bool */ public function isExpired(): bool { if (!$this->expires_at) { return false; } return now()->gt($this->expires_at); } /** * 检查凭证是否即将过期 * * @param int $days 提前天数 * @return bool */ public function isExpiringSoon(int $days = 7): bool { if (!$this->expires_at) { return false; } return now()->addDays($days)->gte($this->expires_at); } /** * 检查凭证是否可用 * * @return bool */ public function isUsable(): bool { return $this->is_active && !$this->isExpired(); } /** * 获取解密后的凭证信息 * * @return array */ public function getDecryptedCredentials(): array { if (!$this->credentials) { return []; } $decrypted = []; foreach ($this->credentials as $key => $value) { try { // 尝试解密,如果失败则返回原值 $decrypted[$key] = is_string($value) ? Crypt::decryptString($value) : $value; } catch (\Exception $e) { $decrypted[$key] = $value; } } return $decrypted; } /** * 设置加密的凭证信息 * * @param array $credentials * @return void */ public function setEncryptedCredentials(array $credentials): void { $encrypted = []; foreach ($credentials as $key => $value) { // 只加密字符串类型的敏感信息 if (is_string($value) && $this->isSensitiveField($key)) { $encrypted[$key] = Crypt::encryptString($value); } else { $encrypted[$key] = $value; } } $this->credentials = $encrypted; } /** * 检查字段是否为敏感信息 * * @param string $field * @return bool */ protected function isSensitiveField(string $field): bool { $sensitiveFields = [ 'api_key', 'api_secret', 'access_token', 'refresh_token', 'client_secret', 'private_key', 'password', 'secret', 'app_secret', 'webhook_secret', ]; return in_array(strtolower($field), $sensitiveFields); } /** * 获取特定的凭证值 * * @param string $key * @param mixed $default * @return mixed */ public function getCredential(string $key, $default = null) { $credentials = $this->getDecryptedCredentials(); return $credentials[$key] ?? $default; } /** * 更新使用统计 * * @return bool */ public function updateUsageStats(): bool { return $this->update([ 'last_used_at' => now(), 'usage_count' => $this->usage_count + 1, ]); } /** * 生成认证头 * * @return array */ public function generateAuthHeaders(): array { $authType = $this->getAuthTypeEnum(); $credentials = $this->getDecryptedCredentials(); $headers = []; switch ($authType) { case AUTH_TYPE::API_KEY: $headers[$authType->getHeaderName()] = $credentials['api_key'] ?? ''; break; case AUTH_TYPE::BEARER: $headers[$authType->getHeaderName()] = $authType->getHeaderPrefix() . ($credentials['access_token'] ?? ''); break; case AUTH_TYPE::BASIC: $username = $credentials['username'] ?? ''; $password = $credentials['password'] ?? ''; $headers[$authType->getHeaderName()] = $authType->getHeaderPrefix() . base64_encode($username . ':' . $password); break; case AUTH_TYPE::JWT: $headers[$authType->getHeaderName()] = $authType->getHeaderPrefix() . ($credentials['jwt_token'] ?? ''); break; case AUTH_TYPE::SIGNATURE: // 签名认证需要根据具体的签名算法生成 $headers['X-Signature'] = $this->generateSignature($credentials); break; case AUTH_TYPE::CUSTOM: // 自定义认证方式 $headers = $credentials['custom_headers'] ?? []; break; } return $headers; } /** * 生成签名 * * @param array $credentials * @return string */ protected function generateSignature(array $credentials): string { // 这里需要根据具体的第三方服务的签名算法实现 // 这是一个示例实现 $appKey = $credentials['app_key'] ?? ''; $appSecret = $credentials['app_secret'] ?? ''; $timestamp = time(); $nonce = uniqid(); $signString = $appKey . $timestamp . $nonce . $appSecret; return hash('sha256', $signString); } /** * 关联第三方服务 * * @return BelongsTo */ public function service(): BelongsTo { return $this->belongsTo(ThirdPartyService::class, 'service_id'); } /** * 验证凭证配置是否完整 * * @return array ['valid' => bool, 'missing_fields' => array] */ public function validateCredentials(): array { $authType = $this->getAuthTypeEnum(); $requiredFields = $authType->getRequiredFields(); $credentials = $this->getDecryptedCredentials(); $missingFields = []; foreach ($requiredFields as $field) { if (empty($credentials[$field])) { $missingFields[] = $field; } } return [ 'valid' => empty($missingFields), 'missing_fields' => $missingFields, ]; } /** * 创建新的凭证 * * @param array $data * @return static */ public static function createCredential(array $data): static { $credential = new static(); $credential->fill($data); // 加密敏感信息 if (isset($data['credentials'])) { $credential->setEncryptedCredentials($data['credentials']); } $credential->save(); return $credential; } }