新版数智员工

This commit is contained in:
wong
2026-03-24 10:39:16 +08:00
parent 1853934d85
commit 7fb61b77a4
123 changed files with 38491 additions and 1018 deletions

View File

@@ -0,0 +1,153 @@
<?php
namespace app\common\service;
use think\Db;
use think\facade\Log;
/**
* 用户 API Key 服务
*
* Key 格式与"场景获客"保持一致:
* 5 组 × 5 位(大小写字母 + 数字),组间用 "-" 连接
* 示例aB3k9-Z8c1Q-0f4Xk-M9n2P-1A2b3
*
* 绑定对象ck_users 表(`users`)中的 `apiKey` 字段
*/
class UserApiKeyService
{
/** 字符集:大小写字母 + 数字 */
private static $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
/**
* 生成一个在 ck_users 中唯一的 API Key
*
* @return string 格式xxxxx-xxxxx-xxxxx-xxxxx-xxxxx
*/
public static function generate(): string
{
$chars = self::$chars;
$charLen = strlen($chars);
while (true) {
$key = '';
for ($i = 0; $i < 5; $i++) {
$segment = '';
for ($j = 0; $j < 5; $j++) {
$segment .= $chars[mt_rand(0, $charLen - 1)];
}
$key .= ($i > 0 ? '-' : '') . $segment;
}
// 确保全局唯一
$exists = Db::name('users')->where('apiKey', $key)->find();
if (!$exists) {
return $key;
}
}
}
/**
* 为指定用户绑定 API Key幂等已有则直接返回没有则生成并写入
*
* @param int $userId ck_users.id
* @return string 该用户的 apiKey
* @throws \RuntimeException
*/
public static function bindOrGet(int $userId): string
{
$user = Db::name('users')
->where('id', $userId)
->where('deleteTime', 0)
->field('id, apiKey')
->find();
if (!$user) {
throw new \RuntimeException('用户不存在');
}
if (!empty($user['apiKey'])) {
return $user['apiKey'];
}
return self::forceGenerate($userId);
}
/**
* 强制为指定用户重新生成 API Key会覆盖旧 Key
*
* @param int $userId ck_users.id
* @return string 新生成的 apiKey
* @throws \RuntimeException
*/
public static function forceGenerate(int $userId): string
{
$user = Db::name('users')
->where('id', $userId)
->where('deleteTime', 0)
->field('id')
->find();
if (!$user) {
throw new \RuntimeException('用户不存在');
}
$apiKey = self::generate();
Db::name('users')
->where('id', $userId)
->update([
'apiKey' => $apiKey,
'updateTime' => time(),
]);
Log::info("UserApiKeyService: 用户 #{$userId} 生成/更新 apiKey");
return $apiKey;
}
/**
* 通过 apiKey 查找用户(用于对外接口身份校验)
*
* @param string $apiKey
* @return array|null ck_users 行,或 nullkey 无效/用户已删除/已禁用)
*/
public static function findUserByKey(string $apiKey): ?array
{
if (empty($apiKey)) {
return null;
}
$user = Db::name('users')
->where('apiKey', $apiKey)
->where('deleteTime', 0)
->where('status', 1)
->find();
return $user ?: null;
}
/**
* 验证签名
*
* 只有三个固定字段参与签名account、timestamp、apiKey
* stringToSign = account + timestamp (按字段名 ASCII 升序拼接值)
* firstMd5 = MD5(stringToSign)
* sign = MD5(firstMd5 + apiKey)
*
* @param string $account 请求中传入的 accountck_users.account
* @param string $timestamp 请求中传入的 timestamp
* @param string $apiKey 用户 apiKey
* @param string $sign 客户端传来的签名
* @return bool
*/
public static function validateSign(string $account, string $timestamp, string $apiKey, string $sign): bool
{
// account < timestampASCII 升序)
$stringToSign = $account . $timestamp;
$firstMd5 = md5($stringToSign);
$expectedSign = md5($firstMd5 . $apiKey);
return hash_equals($expectedSign, $sign);
}
}