feat(服务器资源): 支持按资源配置复制临时密码并强化使用校验

- 新增资源开关 allow_copy_temp_password 并持久化

- 使用资源时强制访问用户名与密码必填并返回中文提示

- 解析 sso 链接提取 SSOToken,按开关返回临时密码
This commit is contained in:
Boen_Shi 2026-04-30 09:53:33 +08:00
parent d2c6ae7fc0
commit 1ec4cbe941
5 changed files with 72 additions and 2 deletions

View File

@ -89,6 +89,7 @@ class ServerResourceController extends Controller
$description = (string) ($permission->description ?? '');
if (preg_match('/资源ID[:]\s*(\d+)/u', $description, $matches) === 1) {
$resourceIds->push((int) $matches[1]);
continue;
}
@ -316,9 +317,12 @@ class ServerResourceController extends Controller
public function useResource(Request $request, int $id): JsonResponse
{
$validated = $request->validate([
'account_name' => ['nullable', 'string', 'max:255'],
'password' => ['nullable', 'string', 'max:255'],
'account_name' => ['required', 'string', 'max:255'],
'password' => ['required', 'string', 'max:255'],
'protocol' => ['required', 'string', 'max:64'],
], [
'account_name.required' => '请输入访问用户名。',
'password.required' => '请输入访问密码。',
]);
$resource = ServerResource::query()->with('parent')->findOrFail($id);
@ -456,6 +460,11 @@ class ServerResourceController extends Controller
], 502);
}
$tempPassword = null;
if ((bool) $resource->allow_copy_temp_password) {
$tempPassword = $this->extractSsoTokenFromUrl($ssoUrl);
}
AccessLog::query()->create([
'user_id' => $user->id,
'server_resource_id' => $resource->id,
@ -493,10 +502,42 @@ class ServerResourceController extends Controller
'bastion_account_id' => $bastionAccount->id,
'client_type' => (string) data_get($result, 'data.client_type', ''),
'response' => $result,
'allow_copy_temp_password' => (bool) $resource->allow_copy_temp_password,
'temp_password' => $tempPassword,
],
]);
}
private function extractSsoTokenFromUrl(string $ssoUrl): ?string
{
if (! str_starts_with($ssoUrl, 'sso://')) {
return null;
}
$encoded = trim(substr($ssoUrl, strlen('sso://')));
$encoded = rtrim($encoded, '/');
if ($encoded === '') {
return null;
}
$decoded = base64_decode($encoded, true);
if ($decoded === false || $decoded === '') {
return null;
}
$payload = json_decode($decoded, true);
if (! is_array($payload)) {
return null;
}
$token = data_get($payload, 'NODE_COMMON.SSOToken');
if (! is_string($token) || trim($token) === '') {
return null;
}
return trim($token);
}
private function syncDirectPermissionsByPivot(ServerResource $resource, Permission $permission, array $syncData): void
{
if (! $resource->parent_id) {

View File

@ -22,6 +22,7 @@ class StoreServerResourceRequest extends FormRequest
'account_id' => ['nullable', 'integer', 'min:1'],
'protocol' => ['nullable', 'string', 'max:64'],
'description' => ['nullable', 'string', 'max:255'],
'allow_copy_temp_password' => ['sometimes', 'boolean'],
'is_active' => ['sometimes', 'boolean'],
];
}

View File

@ -22,6 +22,7 @@ class UpdateServerResourceRequest extends FormRequest
'account_id' => ['nullable', 'integer', 'min:1'],
'protocol' => ['nullable', 'string', 'max:64'],
'description' => ['nullable', 'string', 'max:255'],
'allow_copy_temp_password' => ['sometimes', 'boolean'],
'is_active' => ['sometimes', 'boolean'],
];
}

View File

@ -21,6 +21,7 @@ class ServerResource extends Model
'account_id',
'protocols',
'description',
'allow_copy_temp_password',
'is_active',
];
@ -50,6 +51,7 @@ class ServerResource extends Model
{
return [
'protocols' => 'array',
'allow_copy_temp_password' => 'boolean',
'is_active' => 'boolean',
];
}

View File

@ -0,0 +1,25 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('server_resources', function (Blueprint $table) {
$table->boolean('allow_copy_temp_password')
->default(false)
->after('protocols')
->comment('是否允许用户复制临时密码');
});
}
public function down(): void
{
Schema::table('server_resources', function (Blueprint $table) {
$table->dropColumn('allow_copy_temp_password');
});
}
};