From d7d520058cd9f8a0c032bd36d0609e2a65b76026 Mon Sep 17 00:00:00 2001 From: cc Date: Sat, 20 Jun 2026 20:49:04 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E7=99=BB=E5=BD=95/=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=E9=97=A8=E8=B5=B0=20MySQL=20=E7=9A=84=E8=AF=B4?= =?UTF-8?q?=E6=98=8E=EF=BC=8C=E4=BF=AE=E8=B5=B7=E5=A7=8B=E9=A1=B5=E8=BF=87?= =?UTF-8?q?=E6=9C=9F=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 docs/auth-login-gate.md:入口门 + 登录的 MySQL 后端、表结构、 建库步骤、DATABASE_URL、无库兜底、安全待办 - startpage 文档:层级图删掉已移除的「齿轮」;weather.env 示例补 DATABASE_URL Co-Authored-By: Claude Opus 4.8 --- docs/auth-login-gate.md | 72 ++++++++++++++++++++++++++++++ docs/startpage-weather-location.md | 4 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/auth-login-gate.md diff --git a/docs/auth-login-gate.md b/docs/auth-login-gate.md new file mode 100644 index 0000000..47d8067 --- /dev/null +++ b/docs/auth-login-gate.md @@ -0,0 +1,72 @@ +# 登录 + 开发者入口门(MySQL 后端) + +两道关卡,都由后端 Rust(`Server/src/auth.rs`)实现,**默认实时查 MySQL**: + +1. **入口门(藏门)**:起始页没有任何登录 UI 入口(设置齿轮已移除)。只有访问 + `http:///#` 且 `` 命中后端 `dev_gate` 表,前端才放行到登录页。 +2. **登录(身份)**:登录页提交用户名 + 密码,后端按 `ccuser` 表里的 SHA256 校验。 + +> 入口门只是「把门藏起来」的共享口令,**不是身份凭证**;真正鉴权是第 2 步的登录。 + +## 请求流 + +``` +浏览器 # + └─ POST /api/web/gate { hash } → DevGate.allows() 查 dev_gate 表 → 命中才显示登录页 + 登录页提交 + └─ POST /api/web/login { username, pwd } → UserStore.verify() 查 ccuser 表 → 200 + token / 401 +``` + +- 前端:`Client/src/api/gate.ts`(`checkGate`)、`Client/src/App.tsx`(监听 `hashchange`、防竞态、 + 回起始页时抹掉地址栏 hash)、登录 `Client/src/api/auth.ts`。 +- 后端:`Server/src/auth.rs`、路由 `Server/src/routes/web.rs` 的 `/api/web/gate`、`/api/web/login`。 + +## 存储:MySQL(不缓存,按需查库) + +机器内存紧张,所以**不把整表读进内存**:`UserStore` 与 `DevGate` 都是 +`Db(pool) | Memory(兜底)` 两态,DB 模式下每次校验跑一条索引查询。 +二者**共用同一个 sqlx 懒连接池**(`auth::db_pool_from_env()`,max 5 连接),避免开两份连接。 + +- 连接串来自环境变量 `DATABASE_URL`(线上写在 `/opt/internet-project/weather.env`): + `mysql://KarCharon:@127.0.0.1:3306/InternetProject` +- **未设 `DATABASE_URL`** → 各自回退:用户用内置写死表(仅 `cc`)、入口门读 `GATE_FILE` + (默认 `dev_gate.txt`)再退内置。方便本地无 DB 时开发。 +- 依赖:`sqlx 0.8`,features `runtime-tokio, tls-rustls, mysql, macros`。 + +### 表结构(库 `InternetProject`,utf8mb4) + +```sql +CREATE TABLE ccuser ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(64) NOT NULL UNIQUE, + password_sha256 CHAR(64) NOT NULL, -- SHA256(明文) 的小写 hex + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +CREATE TABLE dev_gate ( + id INT AUTO_INCREMENT PRIMARY KEY, + gate_hash VARCHAR(128) NOT NULL UNIQUE, -- 与前端 URL `#` 后那串原样匹配 + label VARCHAR(64) DEFAULT NULL, -- 备注(开发者名) + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +- 加用户:`INSERT INTO ccuser (username, password_sha256) VALUES ('名', SHA2('明文',256));` +- 加开发者入口:`INSERT INTO dev_gate (gate_hash, label) VALUES ('', '名');` + (DB 模式即时生效,无需重启。) +- 当前 `cc`:登录密码 `192118Lht`;入口 hash `0086e83c9b10`(= 该密码 SHA256 的前 12 位)。 + +## 一次性搭库(服务器本机,MySQL 仅监听 127.0.0.1) + +```sql +CREATE DATABASE InternetProject CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER 'KarCharon'@'localhost' IDENTIFIED WITH mysql_native_password BY ''; +GRANT ALL PRIVILEGES ON InternetProject.* TO 'KarCharon'@'localhost'; +-- 然后建上面两张表、插入初始数据。 +``` + +## 安全注记(待办) + +- 密码是**裸 SHA256(无盐)**,仅保证「不落明文」,不抗暴力破解。对外网开放前应换 + Argon2/bcrypt 这类慢哈希。 +- 登录返回的 `token` 目前**没有任何接口校验**,受保护路由实际尚未真正鉴权(见 + `issue_token` 注释)。加鉴权中间件时再赋予其真实含义。 diff --git a/docs/startpage-weather-location.md b/docs/startpage-weather-location.md index 8232aee..bba8c0b 100644 --- a/docs/startpage-weather-location.md +++ b/docs/startpage-weather-location.md @@ -115,6 +115,8 @@ QWEATHER_PROJECT_ID=项目ID QWEATHER_KEY_ID=凭据ID QWEATHER_PRIVATE_KEY_PATH=/opt/internet-project/qweather.pem PORT=8548 +# 登录 / 入口门走 MySQL(见 docs/auth-login-gate.md) +DATABASE_URL=mysql://KarCharon:******@127.0.0.1:3306/InternetProject ``` 启动: ```bash @@ -150,7 +152,7 @@ ssh root@8.130.143.54 "pkill RustServer; cd /opt/internet-project && \ | 雪类 `400–499` 及冷 `901` | 缓慢飘落雪花 | | 其余 | 无(静态) | -层级:背景图(-z-20) → 渐变 scrim + 半透明黑遮罩(-z-10) → **天气动效(z-0)** → 内容(z-10) → 齿轮(z-30)。 +层级:背景图(-z-20) → 渐变 scrim + 半透明黑遮罩(-z-10) → **天气动效(z-0)** → 内容(z-10)。 ## 本地预览开关(仅 `npm run dev`)