From f16feca4f4a4da1fb34cc33a0db5375e82b2edac Mon Sep 17 00:00:00 2001 From: "WIN-C27C5MSVTPO\\16961" <1696136552@qq.com> Date: Tue, 3 Mar 2026 09:45:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E8=AE=A4=E8=AF=81=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/controller/SystemController.php | 199 +++++++++++++++++++++ app/common/utils/SystemAuth.php | 46 +++++ config/route.php | 5 + config/system_auth.php | 12 ++ 4 files changed, 262 insertions(+) create mode 100644 app/common/controller/SystemController.php create mode 100644 app/common/utils/SystemAuth.php create mode 100644 config/system_auth.php diff --git a/app/common/controller/SystemController.php b/app/common/controller/SystemController.php new file mode 100644 index 0000000..73f84d2 --- /dev/null +++ b/app/common/controller/SystemController.php @@ -0,0 +1,199 @@ +post('user_id'); + $timestamp = (int)$request->post('timestamp'); + $signature = $request->post('signature'); + $systemCode = $request->post('system_code'); + + // 参数验证 + if (empty($userId) || empty($timestamp) || empty($signature)) { + return $this->error('参数不完整', 400); + } + + // 获取配置 + $secret = config('system_auth.shared_secret'); + $expire = config('system_auth.signature_expire', 600); + + // 验证时间戳(10分钟有效期) + if (!SystemAuth::verifyTimestamp($timestamp, $expire)) { + return $this->error('请求已过期', 401); + } + + // 验证签名 + if (!SystemAuth::verifySignature($userId, $timestamp, $signature, $secret)) { + return $this->error('签名验证失败', 401); + } + + // 查找用户 + $user = User::find($userId); + if (!$user) { + return $this->error('用户不存在', 404); + } + + // 验证系统(如果提供了 system_code) + $system = null; + if ($systemCode) { + $system = Systems::where('code', $systemCode)->first(); + if (!$system) { + return $this->error('系统不存在', 404); + } + } + + // 获取 corp_abbr(优先从请求参数获取,否则通过用户 corp_id 查询) + $corpAbbr = $request->post('corp_abbr'); + if (!$corpAbbr && $user->corp_id) { + $corp = \app\common\model\Corp::find($user->corp_id); + $corpAbbr = $corp ? $corp->abbr : ''; + } + + // 构建 JWT payload + $payload = $this->buildJwtPayload($user, $system); + + // 生成 access_token + $jwt = new Jwt(); + $token = $jwt->generateToken($payload); + + // 生成 refresh_token + $refreshToken = $this->generateRefreshToken($user->id, $systemCode ?? ''); + + // 获取 home_url + $homeUrl = $system ? $this->getHome($system->id, $payload) : ''; + + // 记录 token 到 Redis 和 MySQL + $this->recordUserToken($user->id, $token, $systemCode ?? ''); + + // 构建用户信息(去除敏感信息) + $userInfo = [ + 'id' => $user->id, + 'sn' => $user->sn ?? '', + 'name' => $user->name ?? '', + 'avatar' => $user->avatar ?? '', + 'phone' => $user->phone ?? '', + 'email' => $user->email ?? '', + 'sex' => $user->sex ?? '', + 'position' => $user->position ?? '', + 'status' => $user->status ?? 1, + 'corp_id' => $user->corp_id, + ]; + + return $this->success([ + 'access_token' => $token, + 'refresh_token' => $refreshToken, + 'expires_in' => config('jwt.jwt_expiration'), + 'system_code' => $systemCode ?? '', + 'corp_abbr' => $corpAbbr ?? '', + 'login_type' => 'system', + 'home_url' => $homeUrl, + 'user_info' => $userInfo, + ], '认证成功'); + } + + /** + * 构建 JWT payload + */ + private function buildJwtPayload(User $user, ?Systems $system): array + { + $payload = [ + 'user_id' => $user->id, + 'sn' => $user->sn ?? '', + 'name' => $user->name ?? '', + 'iat' => time(), + 'exp' => time() + config('jwt.jwt_expiration'), + ]; + + if ($system) { + $payload['system_code'] = $system->code; + $payload['system_id'] = $system->id; + } + + return $payload; + } + + /** + * 生成 refresh_token + */ + private function generateRefreshToken(int $userId, string $systemCode): string + { + $refreshToken = bin2hex(random_bytes(32)); + + // 存储到 Redis + $key = "refresh_token:{$refreshToken}"; + $expire = config('jwt.jwt_refresh_token_expiration'); + Redis::setex($key, $expire, json_encode([ + 'user_id' => $userId, + 'system_code' => $systemCode, + ])); + + return $refreshToken; + } + + /** + * 获取用户首页地址 + */ + private function getHome(int $systemId, array $payload): string + { + // 简单实现,可以根据实际需求调整 + return ''; + } + + /** + * 记录用户token到 Redis 和 MySQL + */ + private function recordUserToken(int $userId, string $token, string $systemCode): void + { + $request = request(); + $ip = $request ? $request->getRealIp() : ''; + $ua = $request ? $request->header('user-agent', '') : ''; + $now = time(); + $expireAt = $now + config('jwt.jwt_expiration'); + + // Redis Set 用户token集合 + Redis::sAdd("user_tokens:{$userId}:{$systemCode}", $token); + Redis::expire("user_tokens:{$userId}:{$systemCode}", config('jwt.jwt_expiration')); + + // Redis Hash token元信息 + $meta = [ + 'system_code' => $systemCode, + 'login_ip' => $ip, + 'user_agent' => $ua, + 'login_time' => $now, + 'expired_at' => $expireAt, + ]; + Redis::hMSet("user_token_meta:{$token}", $meta); + Redis::expire("user_token_meta:{$token}", config('jwt.jwt_expiration')); + + // MySQL 持久化 + \app\common\model\UserTokenLog::create([ + 'user_id' => $userId, + 'token' => $token, + 'system_code' => $systemCode, + 'login_ip' => $ip, + 'user_agent' => $ua, + 'expired_at' => date('Y-m-d H:i:s', $expireAt), + ]); + } +} diff --git a/app/common/utils/SystemAuth.php b/app/common/utils/SystemAuth.php new file mode 100644 index 0000000..cbef538 --- /dev/null +++ b/app/common/utils/SystemAuth.php @@ -0,0 +1,46 @@ + env('SYSTEM_AUTH_SHARED_SECRET', 'your-shared-secret-string'), + + // 签名有效期(秒),默认10分钟 + 'signature_expire' => 600, + + // Token 有效期(秒) + 'token_expire' => 86400, +];