92 lines
2.6 KiB
PHP
92 lines
2.6 KiB
PHP
<?php
|
||
|
||
namespace app\middleware;
|
||
|
||
use app\model\ApiKey;
|
||
use app\model\Client;
|
||
use app\model\Permission;
|
||
use app\service\Signature;
|
||
use think\Request;
|
||
use think\Response;
|
||
|
||
/**
|
||
* API鉴权中间件
|
||
*/
|
||
class Auth
|
||
{
|
||
/**
|
||
* 处理请求
|
||
*/
|
||
public function handle(Request $request, \Closure $next)
|
||
{
|
||
// 1. 提取必要Headers
|
||
$apiKey = $request->header('X-API-Key');
|
||
$timestamp = $request->header('X-Timestamp');
|
||
$sign = $request->header('X-Sign');
|
||
|
||
if (empty($apiKey) || empty($timestamp) || empty($sign)) {
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '缺少鉴权头: 需要 X-API-Key, X-Timestamp, X-Sign'
|
||
], 401);
|
||
}
|
||
|
||
// 2. 查询API Key(连带查询client和permission)
|
||
$apiKeyObj = ApiKey::with(['client', 'permission'])
|
||
->where('api_key', $apiKey)
|
||
->find();
|
||
|
||
if (!$apiKeyObj) {
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '无效的 API Key'
|
||
], 401);
|
||
}
|
||
|
||
// 3. 检查状态
|
||
if ($apiKeyObj->status != ApiKey::STATUS_ENABLED) {
|
||
return json([
|
||
'code' => 403,
|
||
'msg' => 'API Key 已被禁用'
|
||
], 403);
|
||
}
|
||
|
||
$clientObj = $apiKeyObj->client;
|
||
if (!$clientObj || $clientObj->status != Client::STATUS_ENABLED) {
|
||
return json([
|
||
'code' => 403,
|
||
'msg' => '客户账号已被停用,API 访问被拒绝'
|
||
], 403);
|
||
}
|
||
|
||
// 4. 验证签名
|
||
$params = $request->param();
|
||
if (!Signature::verify($params, $timestamp, $sign, $apiKeyObj->api_secret_hash)) {
|
||
return json([
|
||
'code' => 401,
|
||
'msg' => '签名验证失败'
|
||
], 401);
|
||
}
|
||
|
||
// 5. 检查权限配置
|
||
$permission = Permission::where('api_key_id', $apiKeyObj->id)->find();
|
||
if (!$permission) {
|
||
return json([
|
||
'code' => 403,
|
||
'msg' => '未配置 API 权限,请联系管理员'
|
||
], 403);
|
||
}
|
||
// 6. 将鉴权上下文存入请求
|
||
$request->authContext = [
|
||
'api_key_id' => $apiKeyObj->id,
|
||
'api_key' => $apiKeyObj->api_key,
|
||
'client_id' => $clientObj->id,
|
||
'client_name' => $clientObj->name,
|
||
'permission' => $permission,
|
||
'rate_limit_per_minute' => $apiKeyObj->rate_limit_per_minute,
|
||
'rate_limit_per_day' => $apiKeyObj->rate_limit_per_day,
|
||
];
|
||
|
||
return $next($request);
|
||
}
|
||
} |