# 登录 + 开发者入口门(MySQL 后端) 两道关卡,都由后端 Rust(`Server/src/auth.rs`)实现,**实时查 MySQL(无兜底)**: 1. **入口门(藏门)**:起始页没有任何登录 UI 入口(设置齿轮已移除)。只有访问 `http:///#` 且 `` 命中后端 `dev_gate` 表,前端才放行到登录页。 2. **登录(身份)**:登录页提交用户名 + 密码,后端按 `ccuser` 表里的 SHA256 校验。 > 入口门只是「把门藏起来」的共享口令,**不是身份凭证**;真正鉴权是第 2 步的登录。 > 例外入口:地址栏 `#photo` 是写死的公开入口,**不走入口门**直接显示登录页(去掉顶部 > 负载栏),登录成功进照片墙。详见 [photo-wall.md](photo-wall.md)。第 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`(`ccuser`)、`WallUserStore` (`wall_users`,照片墙登录)、`DevGate`(`dev_gate`)三者各持一个连接池,每次校验跑一条 索引查询。**共用同一个 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`**:未设置则 `db_pool_from_env()` 直接 `panic`,服务拒绝启动。 **不再有任何写死账号 / 文件兜底**(旧的内置写死表、`GATE_FILE`/`dev_gate.txt` 文件模式 已全部删除)——登录与入口门一律走数据库。本地开发也必须先把库搭好(见下)。 - 依赖:`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 ); CREATE TABLE wall_users ( -- 照片墙登录,与 ccuser 物理隔离 id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(64) NOT NULL UNIQUE, password_sha256 CHAR(64) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` - 加开发者用户:`INSERT INTO ccuser (username, password_sha256) VALUES ('名', SHA2('明文',256));` - 加照片墙用户:`INSERT INTO wall_users (username, password_sha256) VALUES ('名', SHA2('明文',256));` - 加开发者入口:`INSERT INTO dev_gate (gate_hash, label) VALUES ('', '名');` (即时生效,无需重启。) - 当前 `cc`:登录密码 `192118Lht`;入口 hash `0086e83c9b10`(= 该密码 SHA256 的前 12 位)。 照片墙用户另有 `UserTest`(文件夹 607)、`UserTest6340`(文件夹 6340)。 ## 一次性搭库(服务器本机 / 本地开发,MySQL/MariaDB 仅监听 127.0.0.1) ```sql CREATE DATABASE InternetProject CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'KarCharon'@'localhost' IDENTIFIED BY ''; GRANT ALL PRIVILEGES ON InternetProject.* TO 'KarCharon'@'localhost'; -- 然后建上面三张表(ccuser / dev_gate / wall_users)、插入初始数据。 ``` > 因为已**去兜底**,本地开发同样要先搭库(无 DB 启动即 panic)。MariaDB 即可,与 MySQL > 兼容(`SHA2()`、`mysql_native_password` 均支持)。启动后端时带上连接串: > `DATABASE_URL='mysql://KarCharon:@127.0.0.1:3306/InternetProject' cargo run` ## 安全注记(待办) - 密码是**裸 SHA256(无盐)**,仅保证「不落明文」,不抗暴力破解。对外网开放前应换 Argon2/bcrypt 这类慢哈希。 - 登录返回的 `token` 目前**没有任何接口校验**,受保护路由实际尚未真正鉴权(见 `issue_token` 注释)。加鉴权中间件时再赋予其真实含义。