97 lines
2.7 KiB
PHP
97 lines
2.7 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\api\controller\v1;
|
||
|
||
use app\common\controller\Api;
|
||
use app\common\library\AgentJwt;
|
||
use app\common\model\ChannelManage;
|
||
use app\admin\model\Admin;
|
||
use Webman\Http\Request;
|
||
use support\Response;
|
||
|
||
/**
|
||
* API v1 鉴权接口
|
||
*/
|
||
class Auth extends Api
|
||
{
|
||
/**
|
||
* Agent Token 类型
|
||
*/
|
||
public const TOKEN_TYPE = 'agent';
|
||
|
||
/**
|
||
* 时间戳有效范围(秒),防止重放攻击
|
||
*/
|
||
protected int $timeTolerance = 300;
|
||
|
||
/**
|
||
* 获取鉴权 Token(GET 请求)
|
||
* 参数仅从 Query 读取:signature、secret、agent_id、time
|
||
* 返回:authtoken;失败返回 code=0 及失败信息
|
||
*/
|
||
public function authToken(Request $request): Response
|
||
{
|
||
$response = $this->initializeApi($request);
|
||
if ($response !== null) {
|
||
return $response;
|
||
}
|
||
|
||
$signature = $request->get('signature', '');
|
||
$secret = $request->get('secret', '');
|
||
$agentId = $request->get('agent_id', '');
|
||
$time = $request->get('time', '');
|
||
|
||
if ($signature === '' || $secret === '' || $agentId === '' || $time === '') {
|
||
return $this->error(__('Parameter signature/secret/agent_id/time can not be empty'));
|
||
}
|
||
|
||
$timestamp = (int) $time;
|
||
if ($timestamp <= 0) {
|
||
return $this->error(__('Invalid timestamp'));
|
||
}
|
||
|
||
$now = time();
|
||
if ($timestamp < $now - $this->timeTolerance || $timestamp > $now + $this->timeTolerance) {
|
||
return $this->error(__('Timestamp expired'));
|
||
}
|
||
|
||
$admin = Admin::where('agent_id', $agentId)->find();
|
||
if (!$admin) {
|
||
return $this->error(__('Agent not found'));
|
||
}
|
||
|
||
$channelId = (int) ($admin->channel_id ?? 0);
|
||
if ($channelId <= 0) {
|
||
return $this->error(__('Agent not found'));
|
||
}
|
||
|
||
$channel = ChannelManage::where('id', $channelId)->find();
|
||
if (!$channel || $channel->secret === '') {
|
||
return $this->error(__('Agent not found'));
|
||
}
|
||
|
||
if ($channel->secret !== $secret) {
|
||
return $this->error(__('Invalid agent or secret'));
|
||
}
|
||
|
||
$expectedSignature = strtoupper(md5($agentId . $secret . $time));
|
||
if (!hash_equals($expectedSignature, $signature)) {
|
||
return $this->error(__('Invalid signature'));
|
||
}
|
||
|
||
$expire = (int) config('buildadmin.agent_auth.token_expire', 86400);
|
||
$payload = [
|
||
'agent_id' => $agentId,
|
||
'channel_id' => $channel->id,
|
||
'admin_id' => $admin->id,
|
||
];
|
||
$authtoken = AgentJwt::encode($payload, $expire);
|
||
|
||
return $this->success('', [
|
||
'authtoken' => $authtoken,
|
||
]);
|
||
}
|
||
}
|