mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-10-29 08:58:22 +08:00
133 lines
5.0 KiB
PHP
133 lines
5.0 KiB
PHP
<?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, '动作不得为空字符串');
|
||
}
|
||
}
|
||
}
|
||
}
|