# Token 认证系统需求文档 ## 1. 项目背景 当前数据同步服务使用单一密码 `admin123123123` 进行认证,存在以下问题: - 无法区分不同客户端的访问 - 无法追踪访问来源和使用情况 - 泄露后需要全局修改所有客户端配置 - 无法对不同客户端进行细粒度的权限控制 ## 2. 核心目标 在保持向后兼容的前提下,增加 Token 认证机制,实现: - 多 Token 管理(不同客户端使用不同 Token) - 访问审计(记录每个 Token 的使用情况) - 权限控制(只读/读写) - 安全增强(失败次数限制、限流、双因素验证) ## 3. 功能需求 ### 3.1 Token 设计 #### Token 生成规则 - **格式**:`dss_` + 32位随机字符串(十六进制) - **示例**:`dss_a1b2c3d4e5f6789012345678901234ab` - **唯一性**:每个 Token 全局唯一 #### Token 属性 ```json { "token": "dss_a1b2c3d4e5f6789012345678901234ab", "name": "生产服务器A", "permission": "readonly", "status": "active", "created_at": "2026-09-13 10:30:00", "expires_at": null, "stats": { "total_requests": 1523, "last_used_at": "2026-09-13 15:20:10", "last_ip": "192.168.1.100", "failed_attempts": 0 }, "access_log": [] } ``` **字段说明**: - `token`: Token 字符串 - `name`: 用户自定义名称(必填,用于识别客户端) - `permission`: 权限级别 - `readonly`: 只读(只能 GET) - `readwrite`: 读写(可 GET/POST/DELETE) - `status`: Token 状态 - `active`: 启用 - `disabled`: 禁用 - `expired`: 已过期 - `created_at`: 创建时间 - `expires_at`: 过期时间(null 表示永久有效) - `stats.total_requests`: 累计请求次数 - `stats.last_used_at`: 最后使用时间 - `stats.last_ip`: 最后使用的 IP 地址 - `stats.failed_attempts`: 连续失败次数(达到 5 次自动禁用) - `access_log`: 访问日志数组(保留最近 20 条) #### 访问日志格式 ```json { "timestamp": "2026-09-13 15:20:10", "ip": "192.168.1.100", "method": "GET", "path": "/api/data/weibo:ykaayk", "status": 200, "error": null } ``` ### 3.2 API 设计 #### 认证方式 **新方式(推荐)**: ```http GET /api/data/weibo:ykaayk X-Token: dss_a1b2c3d4e5f6789012345678901234ab ``` **旧方式(兼容保留)**: ```http GET /api/data/weibo:ykaayk X-Password: admin123123123 ``` **说明**: - `X-Password` 作为超级管理员密码,拥有所有权限,不计入审计日志 - `X-Token` 为普通 Token,受权限和限流控制,记录审计日志 - 两种方式可以并存,优先检查 `X-Token` #### Token 管理 API ##### 1. 创建 Token ```http POST /api/tokens X-Password: admin123123123 Content-Type: application/json { "name": "生产服务器A", "permission": "readonly", "expires_in": null } ``` **参数说明**: - `name`: Token 名称(必填) - `permission`: 权限(必填,`readonly` 或 `readwrite`) - `expires_in`: 过期时间(秒,可选,null 表示永久) - 2592000 = 30天 - 7776000 = 90天 **响应**: ```json { "success": true, "token": "dss_a1b2c3d4e5f6789012345678901234ab", "name": "生产服务器A", "permission": "readonly", "created_at": "2026-09-13 10:30:00", "expires_at": null } ``` ##### 2. 列出所有 Token ```http GET /api/tokens X-Password: admin123123123 ``` **响应**: ```json { "tokens": [ { "token": "dss_a1b2c3...(前12位)", "token_full": "dss_a1b2c3d4e5f6789012345678901234ab", "name": "生产服务器A", "permission": "readonly", "status": "active", "created_at": "2026-09-13 10:30:00", "expires_at": null, "stats": { "total_requests": 1523, "last_used_at": "2026-09-13 15:20:10", "last_ip": "192.168.1.100", "failed_attempts": 0 } } ] } ``` ##### 3. 获取 Token 详情 ```http GET /api/tokens/:token X-Password: admin123123123 ``` **响应**: ```json { "token": "dss_a1b2c3d4e5f6789012345678901234ab", "name": "生产服务器A", "permission": "readonly", "status": "active", "created_at": "2026-09-13 10:30:00", "expires_at": null, "stats": { "total_requests": 1523, "last_used_at": "2026-09-13 15:20:10", "last_ip": "192.168.1.100", "failed_attempts": 0 }, "access_log": [ { "timestamp": "2026-09-13 15:20:10", "ip": "192.168.1.100", "method": "GET", "path": "/api/data/weibo:ykaayk", "status": 200 } ] } ``` ##### 4. 更新 Token 状态 ```http PATCH /api/tokens/:token X-Password: admin123123123 Content-Type: application/json { "status": "disabled" } ``` **可更新字段**: - `status`: `active` 或 `disabled` - `name`: 重命名 **响应**: ```json { "success": true, "token": "dss_a1b2c3d4e5f6789012345678901234ab", "status": "disabled" } ``` ##### 5. 删除 Token(需要二次确认) ```http DELETE /api/tokens/:token X-Password: admin123123123 Content-Type: application/json { "confirm_password": "admin123123123" } ``` **响应**: ```json { "success": true, "message": "Token deleted", "token": "dss_a1b2c3d4e5f6789012345678901234ab" } ``` ### 3.3 权限控制 #### 只读权限(readonly) - ✅ `GET /api/data/:tag` - ✅ `GET /api/data` - ❌ `POST /api/data` - ❌ `DELETE /api/data/:tag` #### 读写权限(readwrite) - ✅ 所有操作 #### 权限验证失败响应 ```json { "error": "Permission denied", "message": "This token has readonly permission", "required": "readwrite" } ``` ### 3.4 安全机制 #### 1. 限流(Rate Limiting) - **规则**:每个 Token 每分钟最多 60 次请求 - **超出后响应**: ```json { "error": "Rate limit exceeded", "message": "Maximum 60 requests per minute", "retry_after": 30 } ``` - **状态码**:429 #### 2. 失败次数限制 - **规则**:连续失败 5 次自动禁用 Token - **失败场景**: - Token 不存在 - Token 已过期 - Token 已禁用 - **自动禁用后响应**: ```json { "error": "Token disabled", "message": "Token has been disabled due to too many failed attempts", "failed_attempts": 5 } ``` #### 3. 过期检测 - 每次请求时检查 `expires_at` - 过期 Token 自动标记为 `expired` 状态 - 过期响应: ```json { "error": "Token expired", "expires_at": "2026-09-10 10:30:00" } ``` #### 4. 双因素验证(敏感操作) 敏感操作需要同时提供 Token 和主密码: - 删除 Token - 修改 Token 权限(从 readonly 改为 readwrite) ### 3.5 数据存储 #### 文件结构 ``` /data/ tokens.json # Token 索引和基本信息 tokens/ dss_a1b2c3...json # 单个 Token 的完整数据 ``` #### tokens.json 格式 ```json { "tokens": { "dss_a1b2c3d4e5f6789012345678901234ab": { "name": "生产服务器A", "permission": "readonly", "status": "active", "created_at": "2026-09-13 10:30:00", "expires_at": null, "file": "tokens/dss_a1b2c3d4e5f6789012345678901234ab.json" } } } ``` #### 单个 Token 文件格式 ```json { "token": "dss_a1b2c3d4e5f6789012345678901234ab", "name": "生产服务器A", "permission": "readonly", "status": "active", "created_at": "2026-09-13 10:30:00", "expires_at": null, "stats": { "total_requests": 1523, "last_used_at": "2026-09-13 15:20:10", "last_ip": "192.168.1.100", "failed_attempts": 0 }, "access_log": [ { "timestamp": "2026-09-13 15:20:10", "ip": "192.168.1.100", "method": "GET", "path": "/api/data/weibo:ykaayk", "status": 200 } ] } ``` ## 4. Web 界面需求 ### 4.1 Token 管理页面 #### 入口 在现有 Web 管理界面(`http://124.220.209.75:5001/`)顶部导航栏添加: ``` [数据管理] [Token 管理] ``` #### Token 列表页 **布局**: ``` +----------------------------------------------------------+ | Token 管理 [+ 创建 Token] | +----------------------------------------------------------+ | 搜索: [__________] 状态: [全部 ▼] 权限: [全部 ▼] | +----------------------------------------------------------+ | 名称 | Token (前12位) | 权限 | 状态 | 最后使用 | 操作 | |----------------|---------------|-------|------|-----------|------------| | 生产服务器A | dss_a1b2c3... | 只读 | 启用 | 5分钟前 | [详情][禁用][删除] | | 测试脚本 | dss_xyz789... | 读写 | 禁用 | 2天前 | [详情][启用][删除] | +----------------------------------------------------------+ ``` **功能**: - 表格展示所有 Token - 搜索框(按名称过滤) - 下拉筛选(状态、权限) - 快速操作按钮(详情、启用/禁用、删除) - Token 列显示前 12 位,点击可复制完整 Token #### 创建 Token 弹框 **触发**:点击 [+ 创建 Token] 按钮 **弹框内容**: ``` +-----------------------------------------------+ | 创建 Token | +-----------------------------------------------+ | Token 名称 * | | [_______________________________________] | | 用于识别客户端,如"生产服务器A" | | | | 权限范围 * | | ○ 只读(仅查询数据) | | ● 读写(可上传、删除数据) | | | | 过期设置 * | | ● 永久有效 | | ○ 30天后过期 | | ○ 90天后过期 | | ○ 自定义: [___] 天 | | | | [取消] [创建] | +-----------------------------------------------+ ``` **验证规则**: - Token 名称:必填,1-50 字符 - 权限范围:必选 - 过期设置:必选 **成功后**: - 关闭弹框 - 显示新创建的 Token 详情弹框(包含完整 Token,提示复制保存) - 刷新列表 #### Token 详情弹框 **触发**: 1. 点击列表中的 [详情] 按钮 2. 创建 Token 成功后自动弹出 **弹框内容**: ``` +-----------------------------------------------+ | Token 详情 | +-----------------------------------------------+ | Token 值 | | [••••••••••••••••••••••••••••] [👁 显示] [📋 复制] | | | | 基本信息 | | 名称: 生产服务器A | | 权限: 只读 | | 状态: 🟢 启用中 | | 创建时间: 2026-09-13 10:30:00 | | 过期时间: 永久有效 | | | | 使用统计 | | 总请求数: 1,523 次 | | 最后使用: 2026-09-13 15:20:10 (5分钟前) | | 最后 IP: 192.168.1.100 | | 失败次数: 0 | | | | 访问日志 (最近 20 条) | | +-------------------------------------------+ | | | 时间 | IP | 操作 | 状态 | | | |------------------|--------------|---------|-----| | | | 15:20:10 | 192.168.1.100| GET ...| 200 | | | | 15:15:05 | 192.168.1.100| GET ...| 200 | | | +-------------------------------------------+ | | | | [关闭] [修改] [删除] | +-----------------------------------------------+ ``` **功能**: - Token 值默认遮罩,点击 [👁 显示] 切换显示/隐藏 - [📋 复制] 按钮复制完整 Token - 状态图标:🟢 启用中 / 🔴 已禁用 / ⏰ 已过期 - 访问日志表格可滚动 - [修改] 按钮打开编辑弹框 - [删除] 按钮触发删除确认 #### 编辑 Token 弹框 **触发**:点击详情弹框中的 [修改] 按钮 **弹框内容**: ``` +-----------------------------------------------+ | 编辑 Token | +-----------------------------------------------+ | Token 名称 * | | [生产服务器A_____________________________] | | | | 状态 | | ● 启用 | | ○ 禁用 | | | | [取消] [保存] | +-----------------------------------------------+ ``` **说明**: - 权限和过期时间创建后不可修改 - 只能修改名称和状态 #### 删除 Token 确认弹框 **触发**:点击 [删除] 按钮 **弹框内容**: ``` +-----------------------------------------------+ | ⚠️ 删除 Token | +-----------------------------------------------+ | 确认要删除以下 Token 吗? | | | | 名称: 生产服务器A | | Token: dss_a1b2c3... (前12位) | | | | ⚠️ 此操作不可恢复,使用此 Token 的客户端将无法访问 | | | | 输入主密码以确认: | | [_______________________________________] | | | | [取消] [确认删除] | +-----------------------------------------------+ ``` **验证**: - 必须输入正确的主密码(`admin123123123`) - 密码错误显示红色提示:"密码错误,请重试" ### 4.2 UI/UX 规范 #### 通知提示 - **成功**:绿色,5 秒自动关闭 - "✅ Token 创建成功" - "✅ Token 已禁用" - "✅ Token 已删除" - **错误**:红色,15 秒自动关闭 - "❌ Token 名称不能为空" - "❌ 主密码错误" - "❌ Token 不存在" - **信息**:蓝色,8 秒自动关闭 - "📋 Token 已复制到剪贴板" #### 表单验证 - 实时验证(输入时) - 错误时红框 + 聚焦 - 验证失败不关闭弹框 #### 异步操作反馈 - 按钮状态:`[创建]` → `[创建中...]` + 禁用 - 操作开始时显示通知:"正在创建 Token..." - 完成后更新状态和通知 #### 颜色规范 - 主色:`#667eea`(紫色) - 成功:`#10b981`(绿色) - 警告:`#f59e0b`(橙色) - 错误:`#ef4444`(红色) - 信息:`#3b82f6`(蓝色) ## 5. 实现技术栈 ### 后端 - **语言**:Lua (OpenResty) - **存储**:JSON 文件系统 - **配置文件**:`nginx/nginx.conf`(需要修改) ### 前端 - **框架**:纯 HTML/CSS/JavaScript(无框架依赖) - **样式**:参考现有 `web/index.html` 风格 - **HTTP 客户端**:Fetch API ## 6. 实现步骤建议 ### Phase 1: 后端 Token 验证逻辑 1. 在 `nginx.conf` 中添加 Token 验证函数 2. 修改现有 API 路由,增加 `X-Token` 认证支持 3. 实现权限检查(readonly vs readwrite) 4. 保留 `X-Password` 向后兼容 ### Phase 2: Token 管理 API 1. 实现 `POST /api/tokens` 创建 Token 2. 实现 `GET /api/tokens` 列出所有 Token 3. 实现 `GET /api/tokens/:token` 获取详情 4. 实现 `PATCH /api/tokens/:token` 更新状态 5. 实现 `DELETE /api/tokens/:token` 删除 Token ### Phase 3: 审计和安全机制 1. 记录每次 Token 使用(时间、IP、操作) 2. 实现限流逻辑(60次/分钟) 3. 实现失败次数统计和自动禁用 4. 实现过期检测 ### Phase 4: Web 界面 1. 在现有 `web/index.html` 顶部添加导航切换 2. 创建 Token 管理页面(列表 + 搜索过滤) 3. 实现创建 Token 弹框 4. 实现 Token 详情弹框 5. 实现编辑和删除功能 ### Phase 5: 测试和文档 1. 手动测试所有 API 端点 2. 验证权限控制和安全机制 3. 更新 README.md 文档 4. 提供 Token 使用示例 ## 7. 向后兼容性 ### 现有客户端 - 使用 `X-Password: admin123123123` 的现有脚本和工具继续正常工作 - 无需立即迁移到 Token 机制 ### 迁移路径 1. 部署新版本(增加 Token 功能) 2. 在 Web 界面创建新 Token 3. 逐步更新客户端配置(从 `X-Password` 改为 `X-Token`) 4. 最终可选择性禁用 `X-Password`(配置开关) ## 8. 测试用例 ### API 测试 ```bash # 1. 创建 Token curl -X POST http://localhost:5001/api/tokens \ -H "X-Password: admin123123123" \ -H "Content-Type: application/json" \ -d '{"name":"测试Token","permission":"readonly","expires_in":null}' # 2. 使用 Token 获取数据 curl http://localhost:5001/api/data/weibo:ykaayk \ -H "X-Token: dss_xxxxx" # 3. 测试只读权限(应该失败) curl -X POST http://localhost:5001/api/data \ -H "X-Token: dss_xxxxx" \ -H "Content-Type: application/json" \ -d '{"tag":"test","type":"token","data":{}}' # 4. 列出所有 Token curl http://localhost:5001/api/tokens \ -H "X-Password: admin123123123" # 5. 禁用 Token curl -X PATCH http://localhost:5001/api/tokens/dss_xxxxx \ -H "X-Password: admin123123123" \ -H "Content-Type: application/json" \ -d '{"status":"disabled"}' # 6. 删除 Token curl -X DELETE http://localhost:5001/api/tokens/dss_xxxxx \ -H "X-Password: admin123123123" \ -H "Content-Type: application/json" \ -d '{"confirm_password":"admin123123123"}' ``` ## 9. 验收标准 ### 功能验收 - ✅ 可以通过 Web 界面创建 Token - ✅ 创建后显示完整 Token 值(一次性展示) - ✅ Token 列表正确显示所有 Token 及其状态 - ✅ 只读 Token 无法执行写操作 - ✅ 读写 Token 可以执行所有操作 - ✅ 访问日志正确记录(时间、IP、操作、状态) - ✅ 限流生效(60次/分钟) - ✅ 连续失败 5 次自动禁用 - ✅ 过期 Token 无法使用 - ✅ 删除 Token 需要二次确认 - ✅ 旧的 `X-Password` 认证继续工作 ### UI/UX 验收 - ✅ 所有弹框居中显示,带遮罩层 - ✅ 表单验证实时生效,红框 + 聚焦 - ✅ 异步操作有加载状态和通知 - ✅ 通知自动关闭(成功5秒,错误15秒) - ✅ Token 值支持显示/隐藏切换 - ✅ 点击复制成功后有反馈 - ✅ 响应式布局,移动端友好 ### 安全验收 - ✅ Token 存储在服务器端,前端只展示一次 - ✅ 主密码验证正确(创建、删除时) - ✅ 限流正确拦截过多请求 - ✅ 失败次数统计准确 - ✅ 权限控制无漏洞 ## 10. 附录:错误码对照表 | 状态码 | 错误信息 | 场景 | |--------|---------|------| | 200 | - | 请求成功 | | 400 | Invalid request | 请求参数错误 | | 401 | Invalid token | Token 不存在或无效 | | 401 | Token disabled | Token 已被禁用 | | 401 | Token expired | Token 已过期 | | 403 | Permission denied | 权限不足(只读 Token 尝试写操作)| | 404 | Token not found | Token 不存在 | | 429 | Rate limit exceeded | 超过限流限制 | | 500 | Internal server error | 服务器内部错误 | --- **文档版本**:v1.0 **创建日期**:2026-09-13 **作者**:Hermes AI Agent **项目路径**:`/home/hermes/projects/data-sync-service`