118 lines
3.3 KiB
PHP
118 lines
3.3 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace HyperfTest\Cases\Integration\Auth;
|
||
|
|
|
||
|
|
use App\Model\ApiKey;
|
||
|
|
use HyperfTest\TestCase;
|
||
|
|
use HyperfTest\Traits\AuthenticatedTestTrait;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* API Key 认证端到端集成测试
|
||
|
|
*
|
||
|
|
* 验证 API Key 能正确访问各业务端点(products / orders / refunds / api-keys),
|
||
|
|
* 以及无效 Key 被拒绝、JWT 认证仍然正常。
|
||
|
|
*
|
||
|
|
* @internal
|
||
|
|
* @coversNothing
|
||
|
|
*/
|
||
|
|
class ApiKeyAuthEndToEndTest extends TestCase
|
||
|
|
{
|
||
|
|
use AuthenticatedTestTrait;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取 admin 用户的 API Key 明文
|
||
|
|
*/
|
||
|
|
protected function getAdminApiKey(): string
|
||
|
|
{
|
||
|
|
// 确保 admin 用户已开启 api_key_enabled
|
||
|
|
$admin_role = $this->fetchAdminRole();
|
||
|
|
$user = $this->fetchUser(static function ($query) use ($admin_role): void {
|
||
|
|
$query->where('status', 1)->where('role_id', $admin_role->id);
|
||
|
|
});
|
||
|
|
$this->runInCoroutine(static function () use ($user): void {
|
||
|
|
if (!$user->api_key_enabled) {
|
||
|
|
$user->api_key_enabled = true;
|
||
|
|
$user->save();
|
||
|
|
}
|
||
|
|
// 清理旧测试 keys,确保不超过上限
|
||
|
|
ApiKey::query()->where('user_id', $user->id)
|
||
|
|
->where('name', 'like', 'E2E Test Key%')
|
||
|
|
->delete();
|
||
|
|
});
|
||
|
|
|
||
|
|
$token = $this->getAdminToken();
|
||
|
|
|
||
|
|
$response = $this->post('/api/v1/me/api-keys', [
|
||
|
|
'name' => 'E2E Test Key ' . bin2hex(random_bytes(4)),
|
||
|
|
], [
|
||
|
|
'Authorization' => 'Bearer ' . $token,
|
||
|
|
]);
|
||
|
|
|
||
|
|
$response->assertStatus(200);
|
||
|
|
|
||
|
|
return $response->json('data.plain_key');
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function apiKeyHeaders(): array
|
||
|
|
{
|
||
|
|
return ['X-API-Key' => $this->getAdminApiKey()];
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 业务端点 API Key 认证 ==========
|
||
|
|
|
||
|
|
public function test_apikey_auth_products_endpoint(): void
|
||
|
|
{
|
||
|
|
$response = $this->get('/api/v1/products', [], $this->apiKeyHeaders());
|
||
|
|
|
||
|
|
$response->assertStatus(200);
|
||
|
|
$response->assertJsonPath('code', 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_apikey_auth_orders_endpoint(): void
|
||
|
|
{
|
||
|
|
$response = $this->get('/api/v1/orders', [], $this->apiKeyHeaders());
|
||
|
|
|
||
|
|
$response->assertStatus(200);
|
||
|
|
$response->assertJsonPath('code', 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_apikey_auth_refunds_endpoint(): void
|
||
|
|
{
|
||
|
|
$response = $this->get('/api/v1/refunds', [], $this->apiKeyHeaders());
|
||
|
|
|
||
|
|
$response->assertStatus(200);
|
||
|
|
$response->assertJsonPath('code', 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_apikey_auth_list_own_keys(): void
|
||
|
|
{
|
||
|
|
$response = $this->get('/api/v1/me/api-keys', [], $this->apiKeyHeaders());
|
||
|
|
|
||
|
|
$response->assertStatus(200);
|
||
|
|
$response->assertJsonPath('code', 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== 认证失败场景 ==========
|
||
|
|
|
||
|
|
public function test_invalid_apikey_returns_401(): void
|
||
|
|
{
|
||
|
|
$response = $this->get('/api/v1/products', [], [
|
||
|
|
'X-API-Key' => 'dh_invalid_key_that_does_not_exist_00000000',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$response->assertStatus(401);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ========== JWT 认证仍正常 ==========
|
||
|
|
|
||
|
|
public function test_jwt_auth_still_works(): void
|
||
|
|
{
|
||
|
|
$response = $this->get('/api/v1/products', [], $this->authHeaders());
|
||
|
|
|
||
|
|
$response->assertStatus(200);
|
||
|
|
$response->assertJsonPath('code', 0);
|
||
|
|
}
|
||
|
|
}
|