140 lines
4.9 KiB
PHP
140 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\ServerResource;
|
|
use Illuminate\Http\Client\ConnectionException;
|
|
use Illuminate\Http\Client\RequestException;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class ServerUserManagementClient
|
|
{
|
|
public function users(ServerResource $server): array
|
|
{
|
|
return $this->request($server, 'get', '/users')->json();
|
|
}
|
|
|
|
public function user(ServerResource $server, string $username): array
|
|
{
|
|
return $this->request($server, 'get', '/users/'.$this->encodePath($username))->json();
|
|
}
|
|
|
|
public function createUser(ServerResource $server, array $payload): array
|
|
{
|
|
return $this->request($server, 'post', '/users', $payload)->json();
|
|
}
|
|
|
|
public function deleteUser(ServerResource $server, string $username): array
|
|
{
|
|
return $this->request($server, 'delete', '/users/'.$this->encodePath($username))->json();
|
|
}
|
|
|
|
public function updatePassword(ServerResource $server, string $username, string $passwordHash): array
|
|
{
|
|
return $this->request($server, 'patch', '/users/'.$this->encodePath($username).'/password', [
|
|
'password_hash' => $passwordHash,
|
|
])->json();
|
|
}
|
|
|
|
public function groups(ServerResource $server): array
|
|
{
|
|
return $this->request($server, 'get', '/groups')->json();
|
|
}
|
|
|
|
public function createGroup(ServerResource $server, string $groupname): array
|
|
{
|
|
return $this->request($server, 'post', '/groups', ['groupname' => $groupname])->json();
|
|
}
|
|
|
|
public function deleteGroup(ServerResource $server, string $groupname): array
|
|
{
|
|
return $this->request($server, 'delete', '/groups/'.$this->encodePath($groupname))->json();
|
|
}
|
|
|
|
public function userGroups(ServerResource $server, string $username): array
|
|
{
|
|
return $this->request($server, 'get', '/users/'.$this->encodePath($username).'/groups')->json();
|
|
}
|
|
|
|
public function syncUserGroups(ServerResource $server, string $username, array $groups, string $mode = 'replace'): array
|
|
{
|
|
return $this->request($server, 'post', '/users/'.$this->encodePath($username).'/groups', [
|
|
'groups' => array_values($groups),
|
|
'mode' => $mode,
|
|
])->json();
|
|
}
|
|
|
|
public function removeUserGroups(ServerResource $server, string $username, array $groups): array
|
|
{
|
|
return $this->request($server, 'delete', '/users/'.$this->encodePath($username).'/groups', [
|
|
'groups' => array_values($groups),
|
|
'mode' => 'append',
|
|
])->json();
|
|
}
|
|
|
|
private function request(ServerResource $server, string $method, string $path, array $payload = [])
|
|
{
|
|
$target = $this->resolveServer($server);
|
|
$baseUrl = rtrim((string) $target->user_api_base_url, '/');
|
|
$token = trim((string) $target->user_api_token);
|
|
|
|
if ($baseUrl === '' || $token === '') {
|
|
throw ValidationException::withMessages([
|
|
'server' => ['该服务器未配置用户管理 API 地址或密钥。'],
|
|
]);
|
|
}
|
|
|
|
try {
|
|
$pending = Http::baseUrl($baseUrl)
|
|
->acceptJson()
|
|
->asJson()
|
|
->timeout((int) config('services.server_user_management.timeout', 15))
|
|
->connectTimeout((int) config('services.server_user_management.connect_timeout', 5))
|
|
->retry(2, 200, throw: false)
|
|
->withToken($token)
|
|
->withOptions([
|
|
'verify' => (bool) config('services.server_user_management.verify_ssl', false),
|
|
]);
|
|
|
|
$response = match ($method) {
|
|
'post' => $pending->post($path, $payload),
|
|
'patch' => $pending->patch($path, $payload),
|
|
'delete' => empty($payload) ? $pending->delete($path) : $pending->send('DELETE', $path, ['json' => $payload]),
|
|
default => $pending->get($path),
|
|
};
|
|
} catch (ConnectionException|RequestException $exception) {
|
|
throw ValidationException::withMessages([
|
|
'server' => ['服务器用户管理 API 调用失败:'.$exception->getMessage()],
|
|
]);
|
|
}
|
|
|
|
if (! $response->successful()) {
|
|
$message = (string) (data_get($response->json(), 'message')
|
|
?: data_get($response->json(), 'detail.message')
|
|
?: data_get($response->json(), 'detail')
|
|
?: '服务器用户管理 API 返回异常');
|
|
|
|
throw ValidationException::withMessages([
|
|
'server' => [$message],
|
|
]);
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
private function resolveServer(ServerResource $server): ServerResource
|
|
{
|
|
if (! $server->parent_id) {
|
|
return $server;
|
|
}
|
|
|
|
return $server->parent()->firstOrFail();
|
|
}
|
|
|
|
private function encodePath(string $value): string
|
|
{
|
|
return rawurlencode($value);
|
|
}
|
|
}
|