BastionSSO/app/Services/ServerUserManagementClient.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);
}
}