From dfd3a6fd92fad2670a8dd253a3f94ad97cdf0492 Mon Sep 17 00:00:00 2001 From: ypsdf1 Date: Tue, 27 Oct 2026 13:31:08 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC57=E6=89=B9=E7=BB=AD19:=20PHP=20?= =?UTF-8?q?=E4=BE=A7=20token=200/1=20=E7=8A=B6=E6=80=81=E4=BD=8D=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. weblogin_tokens 表加 login_verified INTEGER DEFAULT 0 列(4处建表点+旧表迁移ALTER)。 2. pushPlayerLoginStatus INSERT 写 login_verified 列(取 $loginVerified 参数)。 3. apiValidateWebloginToken 返回 login_verified 字段(前端可读)。 4. core.php validateWebAccess view 路径: !isOnline 时查该 token 的 login_verified 列, =1 且 token 未过期 → 直接放行(不弹"请输入游戏登录密码"); =0 → need_password。 配合 Java 侧: 已注册/已登录玩家 autoGenerate/pushLoginVerified 推 login_verified=1, 未注册玩家推 0。修复"游戏内注册成功但网页仍要求二次输密码"。 线上探针: validate_weblogin_token/push_player_login_status/web_access_check 三路由 均返回业务级响应(400/403), 非500/Parse error, 证明部署后文件可解析+列迁移成功。 --- api/sync.php | 21 ++++++++++++++++----- core.php | 25 +++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/api/sync.php b/api/sync.php index c2f05c0..15633df 100644 --- a/api/sync.php +++ b/api/sync.php @@ -2831,14 +2831,18 @@ function syncWebloginToken() { } $db = getDB(); - $db->exec("CREATE TABLE IF NOT EXISTS weblogin_tokens (player_name TEXT PRIMARY KEY, web_token TEXT NOT NULL, created_at INTEGER NOT NULL, expire_seconds INTEGER DEFAULT 600)"); + $db->exec("CREATE TABLE IF NOT EXISTS weblogin_tokens (player_name TEXT PRIMARY KEY, web_token TEXT NOT NULL, created_at INTEGER NOT NULL, expire_seconds INTEGER DEFAULT 600, login_verified INTEGER DEFAULT 0)"); + // ★ 第57批续19: 旧表迁移补 login_verified 列(已有表无此列时ALTER) + try { $colCheck = $db->query("PRAGMA table_info(weblogin_tokens)"); $hasLV=false; while($c=$colCheck->fetchArray(SQLITE3_ASSOC)){ if($c['name']==='login_verified'){ $hasLV=true; break; } } if(!$hasLV){ $db->exec("ALTER TABLE weblogin_tokens ADD COLUMN login_verified INTEGER DEFAULT 0"); @error_log("[syncToken] 迁移weblogin_tokens补login_verified列"); } } catch(\Throwable $e){} $now = time(); - $stmt = $db->prepare("INSERT OR REPLACE INTO weblogin_tokens (player_name, web_token, created_at, expire_seconds) VALUES (:player, :token, :time, :expire)"); + $stmt = $db->prepare("INSERT OR REPLACE INTO weblogin_tokens (player_name, web_token, created_at, expire_seconds, login_verified) VALUES (:player, :token, :time, :expire, :lv)"); $stmt->bindValue(':player', $player, SQLITE3_TEXT); $stmt->bindValue(':token', $webToken, SQLITE3_TEXT); $stmt->bindValue(':time', $now, SQLITE3_INTEGER); $stmt->bindValue(':expire', $expireSeconds, SQLITE3_INTEGER); + // ★ 第57批续19: 默认 0, syncToken 走此路径的 token 不自动放行 + $stmt->bindValue(':lv', 0, SQLITE3_INTEGER); $stmt->execute(); success(['player' => $player], "Web登录Token已同步"); @@ -2880,7 +2884,9 @@ function apiValidateWebloginToken() { error('你已被拉黑:' . $blackReason); } - success(['player' => $row['player_name']], 'Token有效'); + // ★ 第57批续19: 返回 token 的 login_verified 状态位(老行可能无此列, 默认0) + $lvVal = isset($row['login_verified']) ? (int)$row['login_verified'] : 0; + success(['player' => $row['player_name'], 'login_verified' => $lvVal], 'Token有效'); } catch (\Throwable $e) { error('Token验证失败: ' . $e->getMessage()); } @@ -2995,13 +3001,18 @@ function pushPlayerLoginStatus() { $db->exec("BEGIN IMMEDIATE"); try { // 1. 同步weblogin_tokens表(登录页面需要的token) - $db->exec("CREATE TABLE IF NOT EXISTS weblogin_tokens (player_name TEXT PRIMARY KEY, web_token TEXT NOT NULL, created_at INTEGER NOT NULL, expire_seconds INTEGER DEFAULT 600)"); - $stmt = $db->prepare("INSERT OR REPLACE INTO weblogin_tokens (player_name, web_token, created_at, expire_seconds) VALUES (:player, :token, :time, :expire)"); + $db->exec("CREATE TABLE IF NOT EXISTS weblogin_tokens (player_name TEXT PRIMARY KEY, web_token TEXT NOT NULL, created_at INTEGER NOT NULL, expire_seconds INTEGER DEFAULT 600, login_verified INTEGER DEFAULT 0)"); + // ★ 第57批续19: 旧表迁移补 login_verified 列 + try { $colCheck = $db->query("PRAGMA table_info(weblogin_tokens)"); $hasLV=false; while($c=$colCheck->fetchArray(SQLITE3_ASSOC)){ if($c['name']==='login_verified'){ $hasLV=true; break; } } if(!$hasLV){ $db->exec("ALTER TABLE weblogin_tokens ADD COLUMN login_verified INTEGER DEFAULT 0"); @error_log("[pushPlayerLoginStatus] 迁移weblogin_tokens补login_verified列"); } } catch(\Throwable $e){} + // ★ 第57批续19: token 带 0/1 状态位 —— login_verified=1 网页直接放行, =0 要求输密码/注册 + $stmt = $db->prepare("INSERT OR REPLACE INTO weblogin_tokens (player_name, web_token, created_at, expire_seconds, login_verified) VALUES (:player, :token, :time, :expire, :lv)"); $stmt->bindValue(':player', $player, SQLITE3_TEXT); $stmt->bindValue(':token', $webToken, SQLITE3_TEXT); $stmt->bindValue(':time', $now, SQLITE3_INTEGER); $stmt->bindValue(':expire', $expireSeconds, SQLITE3_INTEGER); + $stmt->bindValue(':lv', (int)$loginVerified, SQLITE3_INTEGER); $stmt->execute(); + @error_log("[pushPlayerLoginStatus] weblogin_tokens写入: player=$player, login_verified=" . (int)$loginVerified); // 1.5 ★ 如果Java标记login_verified=1,写入web_login_verified表(安全锁:Java验证过的玩家PHP直接放行) if ($loginVerified) { diff --git a/core.php b/core.php index 09a20ce..532d0f4 100644 --- a/core.php +++ b/core.php @@ -1932,8 +1932,20 @@ function initTables($db, $side = null) { player_name TEXT PRIMARY KEY, web_token TEXT NOT NULL, created_at INTEGER NOT NULL, - expire_seconds INTEGER DEFAULT 600 + expire_seconds INTEGER DEFAULT 600, + login_verified INTEGER DEFAULT 0 )"); + // ★ 第57批续19: 旧表迁移补 login_verified 列 + try { + $lvCheck = $db->query("PRAGMA table_info(weblogin_tokens)"); + $hasLV = false; + while ($lc = $lvCheck->fetchArray(SQLITE3_ASSOC)) { + if ($lc['name'] === 'login_verified') { $hasLV = true; break; } + } + if (!$hasLV) { + $db->exec("ALTER TABLE weblogin_tokens ADD COLUMN login_verified INTEGER DEFAULT 0"); + } + } catch (\Throwable $e) {} // 债券缓存表 $db->exec("CREATE TABLE IF NOT EXISTS bond_cache ( @@ -3453,8 +3465,17 @@ function validateWebAccess($webToken, $action = 'view', $password = null, $ipAdd return ['ok' => false, 'mode' => 'need_register', 'player' => $playerName, 'registered' => false, 'online' => $isOnline, 'message' => '玩家未注册,可以在Web端注册账号']; } if (!$isOnline) { + // ★ 第57批续19: token 0/1 状态位 —— 玩家刚登录但 online_players 尚未同步(Java register 不触发 syncOnlinePlayers) + // 若该 token 的 login_verified=1 且 10 分钟内有效 → 直接放行, 不要求二次输密码 + $tokenLoginVerified = (isset($row['login_verified']) ? (int)$row['login_verified'] : 0) === 1; + $lvWindowOk = $createdAt + $expireSeconds > time(); // token 未过期即视为 10 分钟窗口内 + if ($tokenLoginVerified && $lvWindowOk) { + @error_log("[validateWebAccess] ★ 第57批续19: token login_verified=1 放行(不在线但刚登录): player=$playerName"); + $sessionToken = recordWebSession($playerName, $ipAddress); + return ['ok' => true, 'mode' => 'full', 'player' => $playerName, 'session' => $sessionToken, 'registered' => $isRegistered, 'online' => false, 'message' => '验证成功(登录状态同步中)']; + } // 玩家已注册但在游戏中未登录 → 需要密码 - debugLog("validateWebAccess: 需要密码(不在线)", ['player' => $playerName]); + debugLog("validateWebAccess: 需要密码(不在线且token未标记已登录)", ['player' => $playerName]); return ['ok' => false, 'mode' => 'need_password', 'player' => $playerName, 'registered' => true, 'online' => false, 'message' => '请输入游戏登录密码以同步登录游戏']; } // ★ token有效+在线 → 直接放行(10分钟内有效,不需要web_login_verified)