Files
ulthon_admin/tests/Feature/AuthPayloadTest.php

133 lines
5.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace tests\Feature;
use app\common\constants\AdminConstant;
use app\common\service\AuthService;
use app\common\test\TestCase;
use think\facade\Db;
/**
* AuthService::getAuthPayload 权限载荷构建测试.
*
* 覆盖三组契约:
* a) 超管(AdminConstant::SUPER_ADMIN_ID)→ all === true
* b) 仅授权 system.quick/index 与 system.quick/read 的普通管理员
* → all === false,nodes['system.quick'] 恰为两者,不含 add/edit/delete
* c) 载荷格式:nodes 每个键不含 '/',每个值为非空字符串数组
*
* fixture 沿用 McpServiceTest 既定模式(ulthon-testing 技能约定):
* 事务内自造全新管理员/角色/节点授权,避开 SystemAuthNode 60 秒查询缓存与
* adminInfo autoCache 窗口;tearDown 自动回滚,无残留。
*/
class AuthPayloadTest extends TestCase
{
/** 受测控制器(system.quick 的 index/read 动作节点均经 CurdTrait 注解注册,auth 默认 true). */
private const CONTROLLER = 'system.quick';
/** 授权动作(恰为载荷期望值). */
private const ALLOWED_ACTIONS = ['index', 'read'];
/** 不应出现的动作(同控制器其余 auth 受控动作). */
private const FORBIDDEN_ACTIONS = ['add', 'edit', 'delete'];
/**
* fixture:角色(仅授权 index/read)+ 绑定该角色的启用管理员.
*
* @return int 管理员ID
*/
private function createRestrictedAdmin(): int
{
$roleId = Db::name('system_auth')->insertGetId([
'title' => 'apt' . uniqid(),
'status' => 2, // system_auth 枚举:1=禁用 2=启用
'sort' => 100,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
]);
foreach (self::ALLOWED_ACTIONS as $action) {
Db::name('system_auth_node')->insert([
'auth_id' => $roleId,
'node' => self::CONTROLLER . '/' . $action,
]);
}
return Db::name('system_admin')->insertGetId([
'username' => 'apt_' . uniqid(),
'password' => 'should-not-leak',
'auth_ids' => (string) $roleId,
'status' => 1,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
]);
}
// =========================================================================
// a) 超管
// =========================================================================
public function test_super_admin_payload_is_all_true(): void
{
$service = new AuthService(AdminConstant::SUPER_ADMIN_ID);
$payload = $service->getAuthPayload();
$this->assertTrue($payload['all']);
$this->assertSame([], $payload['nodes']);
}
// =========================================================================
// b) 普通管理员:按角色授权精确聚合
// =========================================================================
public function test_restricted_admin_payload_contains_only_seeded_nodes(): void
{
$adminId = $this->createRestrictedAdmin();
$service = new AuthService($adminId);
$payload = $service->getAuthPayload();
$this->assertFalse($payload['all']);
$this->assertArrayHasKey(self::CONTROLLER, $payload['nodes'], 'payload: ' . json_encode($payload, JSON_UNESCAPED_SLASHES));
$this->assertCount(
count(self::ALLOWED_ACTIONS),
$payload['nodes'][self::CONTROLLER],
'payload: ' . json_encode($payload, JSON_UNESCAPED_SLASHES)
);
$this->assertEqualsCanonicalizing(self::ALLOWED_ACTIONS, $payload['nodes'][self::CONTROLLER]);
foreach (self::FORBIDDEN_ACTIONS as $action) {
$this->assertNotContains($action, $payload['nodes'][self::CONTROLLER]);
}
}
// =========================================================================
// c) 载荷格式契约
// =========================================================================
public function test_payload_nodes_format_contract(): void
{
$adminId = $this->createRestrictedAdmin();
$service = new AuthService($adminId);
$payload = $service->getAuthPayload();
$this->assertFalse($payload['all']);
$this->assertIsArray($payload['nodes']);
$this->assertNotEmpty($payload['nodes'], '受限管理员 nodes 不应为空');
foreach ($payload['nodes'] as $controller => $actions) {
$this->assertIsString($controller);
$this->assertStringNotContainsString('/', $controller, '控制器键不得含 /');
$this->assertIsArray($actions);
$this->assertNotEmpty($actions);
foreach ($actions as $action) {
$this->assertIsString($action);
$this->assertNotSame('', $action, '动作不得为空字符串');
}
}
}
}