115 lines
4.3 KiB
PHP
115 lines
4.3 KiB
PHP
<?php
|
||
|
||
namespace app\common\controller;
|
||
|
||
use think\Controller;
|
||
use think\facade\Log;
|
||
use app\common\service\UserApiKeyService;
|
||
use app\common\util\JwtUtil;
|
||
|
||
/**
|
||
* 对外开放接口 — 鉴权控制器
|
||
*
|
||
* 第三方系统先用 apiKey + sign 换取 JWT Token,
|
||
* 后续所有 /v1/open/* 业务接口只需在 Header 中携带:
|
||
* Authorization: Bearer <token>
|
||
* 即可调用,与存客宝内部接口完全兼容。
|
||
*/
|
||
class OpenAuthController extends Controller
|
||
{
|
||
/**
|
||
* 获取 JWT Token
|
||
* POST /v1/open/auth/token
|
||
*
|
||
* 请求参数:
|
||
* apiKey - 账号专属 API Key(ck_users.apiKey)
|
||
* account - 登录账号(ck_users.account),参与签名
|
||
* timestamp - 秒级时间戳
|
||
* sign - 签名值,算法见签名文档
|
||
*
|
||
* 成功响应:
|
||
* { code: 200, message: "success", data: { token: "xxx", expires_in: 7200 } }
|
||
*/
|
||
public function getToken()
|
||
{
|
||
try {
|
||
$params = $this->request->param();
|
||
|
||
// ── 1. 必填参数校验 ─────────────────────────────────────────
|
||
if (empty($params['apiKey'])) {
|
||
return $this->fail('apiKey不能为空', 400);
|
||
}
|
||
if (empty($params['account'])) {
|
||
return $this->fail('account不能为空', 400);
|
||
}
|
||
if (empty($params['sign'])) {
|
||
return $this->fail('sign不能为空', 400);
|
||
}
|
||
if (empty($params['timestamp'])) {
|
||
return $this->fail('timestamp不能为空', 400);
|
||
}
|
||
|
||
// ── 2. 时间戳时效校验(±5 分钟)──────────────────────────────
|
||
if (abs(time() - intval($params['timestamp'])) > 300) {
|
||
return $this->fail('请求已过期', 400);
|
||
}
|
||
|
||
// ── 3. 用 apiKey 找账号,并校验 account 一致性 ───────────────
|
||
$user = UserApiKeyService::findUserByKey($params['apiKey']);
|
||
if (!$user) {
|
||
return $this->fail('无效的apiKey', 401);
|
||
}
|
||
if ($user['account'] !== $params['account']) {
|
||
return $this->fail('无效的apiKey', 401);
|
||
}
|
||
|
||
// ── 4. 验签(account + timestamp + apiKey)────────────────────
|
||
if (!UserApiKeyService::validateSign(
|
||
$params['account'],
|
||
(string)$params['timestamp'],
|
||
$params['apiKey'],
|
||
$params['sign']
|
||
)) {
|
||
return $this->fail('签名验证失败', 401);
|
||
}
|
||
|
||
// ── 5. 签发 JWT(2 小时有效期)────────────────────────────────
|
||
$expireSeconds = 7200;
|
||
$token = JwtUtil::createToken([
|
||
'id' => (int)$user['id'],
|
||
'account' => $user['account'] ?? '',
|
||
'username' => $user['username'] ?? '',
|
||
'phone' => $user['phone'] ?? '',
|
||
'companyId' => (int)$user['companyId'],
|
||
'typeId' => (int)$user['typeId'],
|
||
'isAdmin' => (int)($user['isAdmin'] ?? 0),
|
||
'via' => 'open_api', // 标记来源,方便日志区分
|
||
], $expireSeconds);
|
||
|
||
Log::info('[OpenAuth] 对外接口登录成功', [
|
||
'userId' => $user['id'],
|
||
'account' => $user['account'],
|
||
'ip' => $this->request->ip(),
|
||
]);
|
||
|
||
return json([
|
||
'code' => 200,
|
||
'message' => 'success',
|
||
'data' => [
|
||
'token' => $token,
|
||
'expires_in' => $expireSeconds,
|
||
],
|
||
]);
|
||
|
||
} catch (\Exception $e) {
|
||
Log::error('[OpenAuth] getToken 异常:' . $e->getMessage());
|
||
return $this->fail('系统错误: ' . $e->getMessage(), 500);
|
||
}
|
||
}
|
||
|
||
private function fail(string $message, int $code = 400)
|
||
{
|
||
return json(['code' => $code, 'message' => $message, 'data' => null]);
|
||
}
|
||
}
|