From 9b822d2d9a280cbeafc17c5e623c3ffc496aa395 Mon Sep 17 00:00:00 2001 From: Yongquan Date: Sun, 1 Nov 2026 12:39:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=89=E8=A3=85=E5=90=91=E5=AF=BC=EF=BC=9A?= =?UTF-8?q?=E5=8A=A0=E7=AE=A1=E7=90=86=E5=91=98=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=EF=BC=8C=E7=B2=BE=E7=AE=80=E4=B8=BA=E5=A1=AB=E8=A1=A8=E5=8D=B3?= =?UTF-8?q?=E8=A3=85=E3=80=81=E8=A3=85=E5=AE=8C=E8=BF=9B=E9=A6=96=E9=A1=B5?= =?UTF-8?q?=20(#1=20#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 管理员账号(用户名 + 口令) 原先只有口令,没有用户名。现在两者都有: - 用户名词入库 settings 的 admin.username(2~32 位,字母数字下划线点连字符) - 口令仍是 bcrypt 哈希存 admin.password_hash,明文不落任何文件 - 登录校验 fb_admin_verify_login():用户名或口令任一不对都返回同一句 「用户名或口令不正确」,且用户名错时也照常跑一次 password_verify,避免用耗时探测账号 - 向后兼容:老部署只设了口令没用户名时,仍可只填口令登录, 并在登录页提示补一个用户名 ## 安装向导精简 按用户要求「没数据就初始化,填完进主页」: - 必填只剩 4 项:网站名称、管理员用户名、口令、确认口令 - 站点描述 / 官方邮箱 / 站点根地址改为 hidden(可留空自动探测) - 密钥、令牌原本就自动生成 - 安装成功后展示网站名称与用户名,2 秒自动跳首页,也有按钮 - 按钮文案改为「完成安装,进入首页」 ## 修掉一个真实 bug 首页把软件说明当成站点描述,导致「软件有 note 时站点描述被顶掉」。 两者是不同的东西:站点描述是全局设置必须始终显示,软件说明另起一行补充。 老基线 D6「首页描述变为新描述」就是被这个 bug 弄失败的。 ## 另一个坑 admin.username 忘了加进 fb_setting_keys() 白名单,fb_set_setting() 会静默丢弃, 表现为「安装时填了用户名,装完却没有」。已补。 验证: - 全新安装流程 32/32(真空站:无 config.php、无 data/*.db) - 老基线 25/25、附件专项 22/22、安装向导 60/60 - PHP 8.5 全部入口 0 弃用 --- admin.php | 37 +++++++++++------ index.php | 10 +++-- install.php | 112 ++++++++++++++++++++++++++++----------------------- lib/util.php | 46 +++++++++++++++++++++ 4 files changed, 138 insertions(+), 67 deletions(-) diff --git a/admin.php b/admin.php index 6a393a8..0846083 100644 --- a/admin.php +++ b/admin.php @@ -25,21 +25,26 @@ if (isset($_GET['logout'])) { /* ---------------- 登录 ---------------- */ $loginErr = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) { - $pw = isset($_POST['admin_password']) ? (string)$_POST['admin_password'] : ''; - $cs = isset($_POST['csrf']) ? (string)$_POST['csrf'] : ''; + $user = isset($_POST['admin_user']) ? (string)$_POST['admin_user'] : ''; + $pw = isset($_POST['admin_password']) ? (string)$_POST['admin_password'] : ''; + $cs = isset($_POST['csrf']) ? (string)$_POST['csrf'] : ''; if (!fb_csrf_ok($cs)) { $loginErr = '会话已过期,请重试。'; } elseif (!fb_rate_check('admin_login', 10)) { $loginErr = '尝试次数过多,请一小时后再试。'; - } elseif (!fb_admin_password_is_set()) { - $loginErr = '本系统还没有设置登录口令,请先运行安装向导(install.php)完成设置。'; - } elseif ($pw !== '' && fb_admin_verify_password($pw)) { - fb_admin_login(); - fb_mod_log('login'); - fb_redirect('admin.php'); } else { - fb_rate_hit('admin_login'); - $loginErr = '口令不正确。'; + $rc = fb_admin_verify_login($user, $pw); + if ($rc === 0) { + fb_admin_login(); + fb_mod_log('login'); + fb_redirect('admin.php'); + } elseif ($rc === 2) { + $loginErr = '本系统还没有配置管理员账号,请先运行安装向导(install.php)完成设置。'; + } else { + fb_rate_hit('admin_login'); + // 不区分「用户名错」还是「口令错」,避免被用来探测账号 + $loginErr = '用户名或口令不正确。'; + } } } @@ -49,13 +54,21 @@ if (!fb_admin_logged_in()) {
← 返回问题列表

管理登录

-

请输入管理员口令(当前仍是 config.php 里的 admin_password 明文,登录后请到「站点设置」改成加密存储)。

+

请输入管理员用户名与口令(当前口令仍是 config.php 里的明文,登录后请到「站点设置」改成加密存储)。

-
尚未设置登录口令,且出厂占位口令已被禁用。请运行 install.php 设定一个。
+
尚未配置管理员账号,且出厂占位口令已被禁用。请运行 install.php 完成初始化。
+ + +
本站只设了口令、没有用户名(旧版安装)。请运行 install.php 补一个用户名;在那之前用户名可留空、只填口令。
+
- + +
-

安装完成 🎉

-

已生成 config.php、建好数据库表。下面是接下来要做的两件事:

+

安装完成

+

已建好数据库、写入站点设置。2 秒后自动进入首页(也可点下方按钮)。

- ① 删除安装文件 —— 请把这个 install.php 从服务器上删掉(已安装态下它会拒绝重装,但删掉更干净)。 - ② 设置口令 —— - - 管理员口令已设成你刚才填的那个,并以 bcrypt 哈希存进数据库;config.php 里没有任何明文口令。 - - 你这次没设口令。在设好之前后台无法登录:请进入 管理后台,在「站点设置 → 登录口令」里设定(或重新运行本向导)。 - - + 网站名称: + 管理员用户名: + 登录入口:admin.php(用户名 + 口令) + 口令存放:bcrypt 哈希,存于数据库;config.php 里没有任何明文口令。
+
+

+ 建议:装好后把 install.php 从服务器删掉。 + 它在已安装状态下会拒绝重装,但删掉更干净。 +

+
+

- 进入问题列表 + 进入首页 管理后台

@@ -323,57 +336,54 @@ if (isset($_POST['do_install'])) { -

二、填写站点信息

+

二、初始化站点

+ + + + - + - - -
- - -
- -

三、设置管理员口令

-

- 口令用来登录管理后台、以及以「官方」身份回复。它以 bcrypt 单向哈希写入数据库,明文不会保存在 config.php 或任何文件里。 - 留空则暂不设定,装完后可在后台补设(补设之前后台不可登录)。 +

管理员账号

+

+ 用来登录管理后台、以「官方」身份回复。口令以 bcrypt 单向哈希存进数据库, + 明文不会写进 config.php 或任何文件。

+ + +
- - + +
-
- +
-

环境体检未通过前无法提交,请先处理标红项。

+

环境体检未通过前无法提交,请先处理上方标红项。

-

安装后再删掉本文件即可。
- 邮件通知(SMTP)与附件上传(阿里云 OSS)都在安装完成后、在后台「站点设置」里配置,这里不需要填。

+

+ 其余设置都已自动处理:站点地址按访问域名自动探测,密钥与令牌已自动生成。
+ 邮件通知(SMTP)与附件上传(OSS)在装好后到后台「站点设置」里配,这里不用填。
+ 装完请删掉 install.php(它本身也会拒绝重复安装)。 +

diff --git a/lib/util.php b/lib/util.php index 13d6c5c..874149e 100644 --- a/lib/util.php +++ b/lib/util.php @@ -300,6 +300,7 @@ function fb_setting_keys() { 'oss.verify', 'oss.image_process', 'oss.use_internal_endpoint', 'moderation.enabled', 'moderation.close_mail_subject', 'admin.password_hash', + 'admin.username', ]; } @@ -452,6 +453,51 @@ function fb_admin_set_password($pw) { return fb_set_setting('admin.password_hash', password_hash((string)$pw, PASSWORD_DEFAULT)); } +/* ---------------- 管理员账号(用户名 + 口令) ---------------- + * 用户名存数据库(admin.username),口令存 bcrypt 哈希(admin.password_hash)。 + * 两者缺一不可:用户名不存在时也照常走一次 password_verify,避免用响应快慢探测账号。 + */ + +/** 管理员用户名;没设过返回空串 */ +function fb_admin_username() { + return trim((string)fb_setting('admin.username', '')); +} + +/** 设置管理员用户名 */ +function fb_admin_set_username($name) { + $name = trim((string)$name); + if ($name === '') { return false; } + return fb_set_setting('admin.username', $name); +} + +/** 账号是否已配置(用户名 + 口令都在) */ +function fb_admin_account_ready() { + return fb_admin_username() !== '' && fb_admin_password_is_set(); +} + +/** + * 校验账号口令。 + * @return int 0=通过 1=账号或口令不对 2=还没配置账号 + */ +function fb_admin_verify_login($user, $pw) { + $user = trim((string)$user); + $pw = (string)$pw; + $u = fb_admin_username(); + + if ($u === '' && !fb_admin_password_is_set()) { return 2; } + + // 用户名没配过(老部署只设了口令):只比口令,向后兼容 + if ($u === '') { + return fb_admin_verify_password($pw) ? 0 : 1; + } + + $hash = (string)fb_setting('admin.password_hash', ''); + // 用户名不对也照常跑一次哈希校验,保持耗时一致 + $pwOk = $hash !== '' ? password_verify($pw, $hash) : fb_admin_verify_password($pw); + $uOk = hash_equals($u, $user); + return ($uOk && $pwOk) ? 0 : 1; +} + /** * 关闭一个 curl 句柄(跨版本安全)。 * --------------------------------------------------------------