feat(api-key): add api_key table, source fields, model and auth middleware

This commit is contained in:
augushong
2026-04-27 00:07:18 +08:00
parent 351808bf07
commit ac4d34884e
5 changed files with 270 additions and 0 deletions

4
app/api/middleware.php Normal file
View File

@@ -0,0 +1,4 @@
<?php
// API中间件通过控制器 $middleware 属性挂载,不需要全局注册
return [];

View File

@@ -0,0 +1,42 @@
<?php
namespace app\middleware;
use app\model\ApiKey;
class ApiKeyAuth
{
public function handle($request, \Closure $next)
{
$raw_key = '';
// 优先从 Authorization: Bearer {key} 提取
$authorization = $request->header('authorization', '');
if (strpos($authorization, 'Bearer ') === 0) {
$raw_key = substr($authorization, 7);
}
// 若无 Bearer尝试从 X-API-Key 请求头获取
if (empty($raw_key)) {
$raw_key = $request->header('x-api-key', '');
}
if (empty($raw_key)) {
return json(['code' => 401, 'msg' => '缺少 API Key', 'data' => null])->code(401);
}
$api_key = ApiKey::verifyKey($raw_key);
if (empty($api_key)) {
return json(['code' => 401, 'msg' => 'API Key 无效或已禁用', 'data' => null])->code(401);
}
// 注入权限到 Request
$request->admin_id = $api_key->admin_id;
$request->api_key_id = $api_key->id;
$request->can_write_own = $api_key->can_write_own;
$request->can_write_other = $api_key->can_write_other;
$request->can_delete = $api_key->can_delete;
return $next($request);
}
}

138
app/model/ApiKey.php Normal file
View File

@@ -0,0 +1,138 @@
<?php
namespace app\model;
use app\common\model\Base;
use think\model\concern\SoftDelete;
/**
* @mixin think\Model
*/
class ApiKey extends Base
{
use SoftDelete;
protected $name = 'api_key';
protected $defaultSoftDelete = 0;
public function admin()
{
return $this->belongsTo(Admin::class, 'admin_id');
}
/**
* 生成API Key
*
* @param int $admin_id
* @param string $name
* @param int $can_write_own
* @param int $can_write_other
* @param int $can_delete
*
* @return string 明文Key仅此一次返回
*/
public static function generateKey($admin_id, $name = '', $can_write_own = 0, $can_write_other = 0, $can_delete = 0)
{
$raw_key = 'ak_' . bin2hex(random_bytes(16));
$hash = md5($raw_key);
self::create([
'admin_id' => $admin_id,
'name' => $name,
'api_key' => $hash,
'can_write_own' => $can_write_own,
'can_write_other' => $can_write_other,
'can_delete' => $can_delete,
'status' => 1,
]);
return $raw_key;
}
/**
* 验证API Key
*
* @param string $raw_key
*
* @return static|null
*/
public static function verifyKey($raw_key)
{
$hash = md5($raw_key);
return self::where('api_key', $hash)->where('status', 1)->find();
}
/**
* 重新生成Key
*
* @param int $id
*
* @return string 新的明文Key
*/
public static function regenerateKey($id)
{
$record = self::find($id);
if (empty($record)) {
return '';
}
$raw_key = 'ak_' . bin2hex(random_bytes(16));
$hash = md5($raw_key);
$record->api_key = $hash;
$record->save();
return $raw_key;
}
/**
* 是否可写自己的文章
*
* @return bool
*/
public function canWriteOwn()
{
return $this->can_write_own == 1;
}
/**
* 是否可写他人的文章
*
* @return bool
*/
public function canWriteOther()
{
return $this->can_write_other == 1;
}
/**
* 是否可删除
* can_delete=0: 不可删除
* can_delete=1: 仅API来源可删除
* can_delete=2: 可删除
*
* @param string|null $source
*
* @return bool
*/
public function canDelete($source = null)
{
$can_delete = (int) $this->can_delete;
if ($can_delete === 0) {
return false;
}
if ($can_delete === 1) {
return $source === 'api';
}
if ($can_delete === 2) {
return true;
}
return false;
}
}