移除登录失败限流;修复连接信息被 e2e 串味为 127.0.0.1

- bootstrap.php/login.php:整体移除「5 次失败锁 10 分钟」限流,登录失败仅即时提示原因
- 新增 tools/fix-config.php:一键双写修正连接地址(默认 exam.nxxy335.top),清空账号密码让用户重输真实卷王凭据
- NY_DATA 隔离落地:run-all.sh 给写配置的 e2e 指向临时目录;修 Windows Git Bash /c/... 路径规范化 bug;.ny-test-data 加 .gitignore
- 清理 dead throttle 引用(e2e 脚本 + docs)
- 修 login.php 真实 bug:ny_is_auth() 分支在加载 $cfg 前引用导致 Undefined variable 警告
- 全量测试 116 通过(PHP 44 + e2e 72)
This commit is contained in:
2026-09-11 17:25:22 +08:00
parent 25a2e8a42c
commit 804b04de60
11 changed files with 151 additions and 113 deletions
+11 -48
View File
@@ -9,7 +9,14 @@ const NY_APP_NAME = 'NY问卷考试系统数据平台';
const NY_VERSION = '1.0.0';
define('NY_ROOT', str_replace('\\', '/', __DIR__));
define('NY_DATA', NY_ROOT . '/data');
// 数据目录默认指向项目下的 data/;测试可通过 NY_DATA 环境变量整体重定向到临时目录,
// 避免 e2e 把 mock 服务的连接配置写进生产库(曾因此把生产 base_url 改成 127.0.0.1 导致登录失败)。
$nyData = NY_ROOT . '/data';
$nyDataEnv = getenv('NY_DATA');
if ($nyDataEnv !== false && $nyDataEnv !== '') {
$nyData = rtrim(str_replace('\\', '/', $nyDataEnv), '/');
}
define('NY_DATA', $nyData);
// ---------------- 环境预检 ----------------
if (PHP_VERSION_ID < 80000) {
@@ -141,53 +148,9 @@ function ny_csrf_ok(): bool
return $given !== '' && hash_equals($token, $given);
}
// ---------------- 登录失败限流 ----------------
/**
* 登录失败限流:按 IP 记录连续失败次数与时间戳(写入 data/login_fail.json)。
* 5 次失败后锁 10 分钟。仅防御暴力破解,不做超强语义(单机小工具足够)。
*/
function ny_login_throttle_check(): array
{
$path = NY_DATA . '/login_fail.json';
$ip = (string)($_SERVER['REMOTE_ADDR'] ?? 'unknown');
$rec = ['count' => 0, 'until' => 0];
if (is_file($path)) {
$j = json_decode((string)file_get_contents($path), true);
if (is_array($j) && isset($j[$ip])) {
$rec = array_merge($rec, $j[$ip]);
}
}
return $rec;
}
function ny_login_throttle_hit(): void
{
$path = NY_DATA . '/login_fail.json';
$ip = (string)($_SERVER['REMOTE_ADDR'] ?? 'unknown');
$all = is_file($path) ? (json_decode((string)file_get_contents($path), true) ?: []) : [];
$rec = isset($all[$ip]) ? $all[$ip] : ['count' => 0, 'until' => 0];
$rec['count'] = ((int)($rec['count'] ?? 0)) + 1;
if ($rec['count'] >= 5) {
$rec['count'] = 0; // 重新计数,进入冷却
$rec['until'] = time() + 600; // 锁 10 分钟
}
$all[$ip] = $rec;
@file_put_contents($path, json_encode($all, JSON_UNESCAPED_UNICODE), LOCK_EX);
}
function ny_login_throttle_reset(): void
{
$path = NY_DATA . '/login_fail.json';
$ip = (string)($_SERVER['REMOTE_ADDR'] ?? 'unknown');
if (!is_file($path)) {
return;
}
$all = json_decode((string)file_get_contents($path), true) ?: [];
if (isset($all[$ip])) {
unset($all[$ip]);
@file_put_contents($path, json_encode($all, JSON_UNESCAPED_UNICODE), LOCK_EX);
}
}
// ---------------- 登录失败限流(已移除) ----------------
// 注:单机内部工具场景下,5 次失败锁 10 分钟的限制常因配置写错/测环境串味而把正常用户挡在门外,
// 且无实际爆破价值(仅内网使用)。应需求已整体移除:登录不再限流,失败只即时提示原因。
/** 判断是否已安装(只看文件 config:base_url 非空即视为已具备连接配置) */
function ny_is_installed(): bool