From 0e35be59f63f2853c473fb5023e81720fe02ff3b Mon Sep 17 00:00:00 2001 From: wsb1224 Date: Sun, 16 Nov 2025 19:56:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=8F=A3=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 2 +- DEPLOYMENT_GUIDE.md | 329 -------------------------- README.md | 4 +- REFACTOR_NOTES.md | 298 ----------------------- app/__init__.py | 3 + app/api/version.py | 30 ++- app/web/templates/version/create.html | 123 ++++++++-- instance/kamaxitong.db | Bin 90112 -> 90112 bytes tests/test_validator.py | 2 +- 9 files changed, 134 insertions(+), 657 deletions(-) delete mode 100644 DEPLOYMENT_GUIDE.md delete mode 100644 REFACTOR_NOTES.md diff --git a/.env b/.env index f0a5683..52d6ec8 100644 --- a/.env +++ b/.env @@ -23,7 +23,7 @@ MAX_UNBIND_TIMES=3 LICENSE_KEY_LENGTH=32 LICENSE_KEY_PREFIX= -FRONTEND_DOMAIN=http://km.taisan.online +FRONTEND_DOMAIN=http://127.0.0.1:5000 # API配置 diff --git a/DEPLOYMENT_GUIDE.md b/DEPLOYMENT_GUIDE.md deleted file mode 100644 index f2d3b91..0000000 --- a/DEPLOYMENT_GUIDE.md +++ /dev/null @@ -1,329 +0,0 @@ -# 账号管理系统重构部署指南 - -## 快速开始 - -### 1. 备份现有系统 - -```bash -# 备份数据库 -mysqldump -u root -p your_database > backup_$(date +%Y%m%d_%H%M%S).sql - -# 备份应用文件 -tar -czf app_backup_$(date +%Y%m%d_%H%M%S).tar.gz app/ migrations/ - -# 备份配置文件 -cp config.py config.py.bak -``` - -### 2. 应用迁移 - -```bash -# 进入项目目录 -cd /path/to/KaMiXiTong - -# 应用数据库迁移 -flask db upgrade - -# 或手动执行 -alembic upgrade head -``` - -### 3. 重启应用 - -```bash -# 如果使用systemd -sudo systemctl restart kamixitong - -# 如果使用gunicorn -sudo killall gunicorn -# 然后重新启动 -gunicorn -w 4 -b 0.0.0.0:5000 run:app & - -# 如果直接运行 -python run.py -``` - -### 4. 验证部署 - -```bash -# 运行测试脚本 -python test_refactored_admin.py -``` - -## 详细部署步骤 - -### 步骤1: 准备工作 - -确认以下环境: -- Python 3.7+ -- MySQL 5.7+ 或 PostgreSQL -- Flask-Migrate 已安装 - -```bash -pip list | grep -E "Flask|flask-migrate|sqlalchemy" -``` - -### 步骤2: 检查代码文件 - -确认以下文件已存在: -- `app/api/admin.py` (重构后) -- `app/models/audit_log.py` (新建) -- `app/web/templates/admin/list.html` (重构后) -- `migrations/versions/20241111_add_soft_delete_to_admin.py` -- `migrations/versions/20241111_create_audit_log.py` - -### 步骤3: 停止应用 - -确保没有活跃的用户连接: -```bash -# 查看活跃连接 -lsof -i :5000 - -# 停止应用 -sudo systemctl stop kamixitong -# 或 -pkill -f "gunicorn.*run:app" -``` - -### 步骤4: 应用迁移 - -```bash -# 初始化迁移仓库(如果还没有) -flask db init - -# 生成迁移文件(可选,文件已存在) -# flask db migrate -m "Add soft delete fields to admin" -# flask db migrate -m "Create audit_log table" - -# 升级数据库 -flask db upgrade - -# 验证迁移 -flask db current -# 应该看到: add_soft_delete_admin 和 create_audit_log -``` - -### 步骤5: 验证表结构 - -```sql --- 连接到数据库 -mysql -u root -p - --- 检查admin表 -DESCRIBE admin; --- 应该看到: is_deleted, delete_time 字段 - --- 检查audit_log表 -DESCRIBE audit_log; --- 应该存在audit_log表 -``` - -### 步骤6: 启动应用 - -```bash -# 启动应用 -python run.py -# 或 -gunicorn -w 4 -b 0.0.0.0:5000 run:app & - -# 检查日志 -tail -f app.log -``` - -### 步骤7: 功能测试 - -#### 测试1: 登录系统 -1. 访问登录页面 -2. 使用超级管理员账号登录 -3. 确认可以访问管理后台 - -#### 测试2: 账号管理 -1. 进入"账号管理"页面 -2. 创建新账号 -3. 编辑账号 -4. 启用/禁用账号 -5. 删除账号(验证软删除) -6. 查看审计日志 - -#### 测试3: 验证新功能 - -```bash -# 访问审计日志表 -mysql -u root -p -e "SELECT * FROM audit_log ORDER BY create_time DESC LIMIT 10;" - -# 查看已删除的账号 -mysql -u root -p -e "SELECT admin_id, username, is_deleted, delete_time FROM admin WHERE is_deleted = 1;" -``` - -## 回滚方案 - -如果遇到问题,可以回滚到原版本: - -### 方案1: 回滚数据库 - -```bash -# 查看迁移历史 -flask db history - -# 回滚到特定版本 -flask db downgrade add_soft_delete_admin - -# 或完全回滚 -flask db downgrade base -``` - -### 方案2: 恢复备份 - -```bash -# 恢复数据库 -mysql -u root -p your_database < backup_YYYYMMDD_HHMMSS.sql - -# 恢复应用文件 -tar -xzf app_backup_YYYYMMDD_HHMMSS.tar.gz - -# 重启应用 -sudo systemctl restart kamixitong -``` - -### 方案3: 手动回滚 - -如果自动回滚失败,手动执行: - -```sql --- 删除audit_log表 -DROP TABLE IF EXISTS audit_log; - --- 删除admin表字段 -ALTER TABLE admin DROP COLUMN is_deleted; -ALTER TABLE admin DROP COLUMN delete_time; -``` - -## 性能优化建议 - -### 1. 审计日志归档 - -```sql --- 归档6个月前的日志 -CREATE TABLE audit_log_archive AS -SELECT * FROM audit_log -WHERE create_time < DATE_SUB(NOW(), INTERVAL 6 MONTH); - --- 清理旧日志 -DELETE FROM audit_log -WHERE create_time < DATE_SUB(NOW(), INTERVAL 6 MONTH); -``` - -### 2. 添加索引 - -```sql --- 为常用查询添加索引 -CREATE INDEX idx_admin_status ON admin(status); -CREATE INDEX idx_admin_username ON admin(username); -``` - -### 3. 监控查询性能 - -```sql --- 慢查询监控 -SET long_query_time = 2; -SET slow_query_log = 1; -``` - -## 常见问题解决 - -### Q1: 迁移失败 - -**错误:** `Target database is not up to date` - -**解决:** -```bash -# 标记当前版本 -flask db stamp head - -# 重新迁移 -flask db upgrade -``` - -### Q2: 权限错误 - -**错误:** `Access denied for user` - -**解决:** -```sql --- 授权 -GRANT ALL PRIVILEGES ON your_database.* TO 'your_user'@'localhost'; -FLUSH PRIVILEGES; -``` - -### Q3: 审计日志记录失败 - -**错误:** `Table 'audit_log' doesn't exist` - -**解决:** -```bash -# 手动应用迁移 -alembic upgrade create_audit_log -``` - -### Q4: 登录失败 - -**错误:** `管理员不存在` - -**解决:** -检查数据库中是否有超级管理员账号: -```sql -SELECT admin_id, username, role, status, is_deleted FROM admin WHERE role = 1 AND status = 1 AND is_deleted = 0; -``` - -如果没有,创建一个: -```sql -INSERT INTO admin (username, password_hash, email, role, status, is_deleted) -VALUES ('admin', '', 'admin@example.com', 1, 1, 0); -``` - -## 监控和维护 - -### 日常检查 - -1. **查看应用日志** - ```bash - tail -f app.log | grep -E "ERROR|CRITICAL" - ``` - -2. **检查数据库状态** - ```sql - SHOW PROCESSLIST; - SHOW TABLE STATUS; - ``` - -3. **监控审计日志增长** - ```sql - SELECT COUNT(*) FROM audit_log WHERE create_time > CURDATE(); - ``` - -### 定期维护 - -1. **每月归档审计日志** -2. **清理过期的已删除账号** (可选) -3. **优化数据库表** (`OPTIMIZE TABLE`) -4. **备份数据库** - -## 联系支持 - -如果遇到问题: -1. 查看 `REFACTOR_NOTES.md` 了解详细变更 -2. 运行 `test_refactored_admin.py` 进行诊断 -3. 检查应用日志和数据库日志 -4. 如需帮助,请提供: - - 错误日志 - - 数据库版本 - - Python版本 - - 操作系统版本 - ---- - -**重要提示:** -- 部署前务必备份数据 -- 在测试环境先进行验证 -- 保留原有的admin_old.py和list_old.html作为备份 -- 建议在低峰期进行部署 diff --git a/README.md b/README.md index eda2436..ac7fdcb 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ KaMiXiTong/ │ ├── test_api.py # API测试 │ └── test_models.py # 模型测试 ├── docs/ # 文档 -│ ├── API.md # API文档 │ ├── INTEGRATION.md # 集成文档 │ ├── EXAMPLES.md # 使用示例 │ └── FASTAPI.md # FastAPI接口文档 @@ -136,7 +135,8 @@ gunicorn -w 4 -b 0.0.0.0:5000 run:app ## 文档 -- [API文档](docs/API.md) +为了更好地管理和使用项目文档,请参考 [文档整理指南](DOCUMENTATION_GUIDE.md)。 + - [集成指南](docs/INTEGRATION.md) - [使用示例](docs/EXAMPLES.md) - [FastAPI接口文档](docs/FASTAPI.md) diff --git a/REFACTOR_NOTES.md b/REFACTOR_NOTES.md deleted file mode 100644 index a448e5f..0000000 --- a/REFACTOR_NOTES.md +++ /dev/null @@ -1,298 +0,0 @@ -# 账号管理系统重构说明 - -## 概述 - -本次重构彻底改进了账号管理系统,从后端API到前端页面都进行了全面优化。重构基于第一性原理思考,采用更现代、更安全的架构。 - -## 重构前后对比 - -### 后端改进 - -| 方面 | 重构前 | 重构后 | -|------|--------|--------| -| 错误处理 | 基础try-catch | 装饰器统一异常处理,分类错误码 | -| 响应格式 | 不统一 | 统一响应结构: `{success, data, message, code}` | -| 数据验证 | 分散在多处 | 统一的验证函数,前后端一致 | -| 删除方式 | 硬删除(物理删除) | 软删除(标记删除) | -| 审计日志 | 无 | 完整的审计日志系统 | -| 日志记录 | 只记录错误 | 记录所有操作详情 | -| 安全性 | 基础验证 | 强验证+权限控制 | -| 代码复用 | 重复代码较多 | 模块化,函数复用 | - -### 前端改进 - -| 方面 | 重构前 | 重构后 | -|------|--------|--------| -| 状态管理 | 散乱 | IIFE模式,状态统一管理 | -| DOM操作 | 频繁使用innerHTML | DOM创建+事件委托 | -| 错误处理 | 简单alert | 优雅的通知系统 | -| 事件绑定 | 重复绑定 | 事件委托避免重复 | -| 代码结构 | 函数式 | 模块化(IIFE) | -| 用户体验 | 基础 | 加载状态、实时反馈 | -| 表单验证 | 基础 | 前后端双重验证 | - -## 核心改进 - -### 1. 统一响应格式 - -```python -{ - "success": bool, # 操作是否成功 - "data": any, # 返回数据 - "message": str, # 提示信息 - "code": int # 状态码 -} -``` - -**优点:** -- 前端处理更简单 -- 错误信息更清晰 -- 便于调试和日志分析 - -### 2. 软删除机制 - -- **添加字段:** `is_deleted`, `delete_time` -- **查询过滤:** 自动过滤已删除记录 -- **安全保护:** 防止数据丢失 - -### 3. 审计日志 - -记录所有管理员操作: -- 操作类型: CREATE, UPDATE, DELETE, TOGGLE_STATUS -- 操作人: admin_id -- 目标: target_type, target_id -- 详情: details (JSON格式) -- 环境: IP地址, User-Agent - -### 4. 统一验证 - -- `validate_username()`: 用户名验证 -- `validate_password()`: 密码强度验证 -- `validate_email()`: 邮箱格式验证 -- `validate_admin_data()`: 管理员数据综合验证 - -### 5. 异常处理装饰器 - -```python -@handle_exceptions -def api_function(): - # 异常自动处理 - # 统一错误响应 - # 自动回滚事务 -``` - -### 6. 权限验证装饰器 - -```python -@require_admin -def protected_function(): - # 自动检查登录状态 - # 自动检查超级管理员权限 - # 统一权限错误响应 -``` - -## 文件变更 - -### 新增文件 - -1. **app/models/audit_log.py** - 审计日志模型 -2. **app/api/admin_refactored.py** - 重构后的API(已替换原文件) -3. **app/web/templates/admin/list_refactored.html** - 重构后的前端页面(已替换原文件) -4. **migrations/versions/20241111_add_soft_delete_to_admin.py** - 添加软删除字段迁移 -5. **migrations/versions/20241111_create_audit_log.py** - 创建审计日志表迁移 -6. **test_refactored_admin.py** - 测试脚本 - -### 备份文件 - -1. `app/api/admin_old.py` - 原API文件备份 -2. `app/web/templates/admin/list_old.html` - 原前端页面备份 - -## 数据库迁移 - -### 迁移1: 添加软删除字段 - -```bash -flask db upgrade -# 或 -alembic upgrade head -``` - -**变更内容:** -- 添加 `is_deleted` 字段 (默认0) -- 添加 `delete_time` 字段 -- 创建索引 `ix_admin_is_deleted` - -### 迁移2: 创建审计日志表 - -```bash -# 迁移1完成后自动执行 -# 或手动执行 -flask db stamp add_soft_delete_admin -flask db upgrade -``` - -**变更内容:** -- 创建 `audit_log` 表 -- 添加外键关联 -- 创建索引 - -## API变更 - -### 响应结构统一 - -所有API现在返回统一格式: - -```json -{ - "success": true/false, - "data": {...}, // 成功时返回数据 - "message": "提示信息", - "code": 0 // 状态码 -} -``` - -### 状态码定义 - -```python -class ResponseCode: - SUCCESS = 0 # 成功 - VALIDATION_ERROR = 1001 # 验证错误 - AUTHENTICATION_FAILED = 1002 # 认证失败 - PERMISSION_DENIED = 1003 # 权限不足 - NOT_FOUND = 1004 # 资源不存在 - DUPLICATE_USERNAME = 2001 # 用户名重复 - INVALID_DATA = 2002 # 无效数据 - CANNOT_DELETE_SELF = 2003 # 不能删除自己 - CANNOT_DISABLE_SELF = 2004 # 不能禁用自己 - SERVER_ERROR = 5000 # 服务器错误 -``` - -## 前端改进 - -### 1. 模块化代码结构 - -使用IIFE模式封装: - -```javascript -(function() { - 'use strict'; - - // 状态管理 - const state = { - currentPage: 1, - searchParams: {...}, - isLoading: false - }; - - // 事件处理 - function bindEvents() {...} - - // 数据加载 - function loadAdmins() {...} - - // 初始化 - document.addEventListener('DOMContentLoaded', init); -})(); -``` - -### 2. 事件委托 - -使用事件委托减少内存泄漏: - -```javascript -elements.adminList.addEventListener('click', function(e) { - const target = e.target.closest('button'); - if (!target) return; - - if (target.classList.contains('edit-btn')) { - // 编辑逻辑 - } else if (target.classList.contains('delete-btn')) { - // 删除逻辑 - } -}); -``` - -### 3. DOM安全操作 - -使用createElement替代innerHTML: - -```javascript -const tr = document.createElement('tr'); -const td = document.createElement('td'); -td.textContent = admin.username; // 防止XSS -tr.appendChild(td); -``` - -### 4. 用户体验优化 - -- 加载状态指示 -- 优雅的错误通知 -- 实时数据更新 -- 表单验证反馈 - -## 测试 - -运行测试脚本: - -```bash -python test_refactored_admin.py -``` - -测试覆盖: -1. Admin模型基本功能 -2. 软删除功能 -3. 审计日志记录 -4. 数据验证函数 -5. 统一响应格式 - -## 部署步骤 - -1. **备份数据库** - ```bash - # 备份当前数据库 - mysqldump -u user -p database > backup.sql - ``` - -2. **应用迁移** - ```bash - flask db upgrade - ``` - -3. **重启应用** - ```bash - # 如果使用gunicorn - sudo systemctl restart kamixitong - - # 或直接运行 - python run.py - ``` - -4. **验证部署** - - 访问账号管理页面 - - 创建测试账号 - - 查看审计日志 - -## 已知问题和限制 - -1. **兼容性**: 现有已删除的硬删除记录需要手动处理 -2. **性能**: 审计日志会逐渐增大,建议定期归档 -3. **权限**: 当前只有超级管理员可以管理账号 - -## 未来改进计划 - -1. **批量操作**: 支持批量启用/禁用/删除 -2. **角色细分**: 支持更多角色类型 -3. **操作日志查看**: 在管理界面查看审计日志 -4. **数据导出**: 支持导出账号数据 -5. **API限流**: 添加API访问频率限制 - -## 总结 - -本次重构显著提升了系统的: -- **安全性**: 软删除+审计日志 -- **可维护性**: 模块化+统一规范 -- **可观测性**: 完整的日志记录 -- **用户体验**: 实时反馈+优雅交互 -- **代码质量**: 减少重复+提高复用 - -通过这次重构,账号管理系统达到了生产级别的标准,具备了更好的扩展性和维护性。 diff --git a/app/__init__.py b/app/__init__.py index 2346763..b602c05 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -5,6 +5,7 @@ from flask_login import LoginManager from flask_migrate import Migrate from config import config from flask_wtf.csrf import CSRFProtect +from flask_cors import CORS import logging from logging.handlers import RotatingFileHandler @@ -13,6 +14,7 @@ db = SQLAlchemy() login_manager = LoginManager() migrate = Migrate() csrf = CSRFProtect() +cors = CORS() def create_app(config_name='default'): """应用工厂函数""" @@ -48,6 +50,7 @@ def create_app(config_name='default'): login_manager.init_app(app) migrate.init_app(app, db) csrf.init_app(app) + cors.init_app(app, resources={r"/api/*": {"origins": "*"}}) # 配置登录管理器 login_manager.login_view = 'web.login' diff --git a/app/api/version.py b/app/api/version.py index b80088c..d6adc22 100644 --- a/app/api/version.py +++ b/app/api/version.py @@ -169,6 +169,18 @@ def create_version(): current_app.logger.warning(f"版本号已存在: product_id={product_id}, version_num={version_num}") return jsonify({'success': False, 'message': '版本号已存在'}), 400 + # 验证文件链接格式(如果提供了链接) + if download_url: + from urllib.parse import urlparse + try: + result = urlparse(download_url) + if not all([result.scheme, result.netloc]): + current_app.logger.warning(f"无效的文件链接格式: {download_url}") + return jsonify({'success': False, 'message': '文件链接格式无效'}), 400 + except Exception as e: + current_app.logger.warning(f"文件链接验证失败: {str(e)}") + return jsonify({'success': False, 'message': '文件链接格式无效'}), 400 + current_app.logger.info(f"创建版本对象: product_id={product_id}, version_num={version_num}") version = Version( product_id=product_id, @@ -198,7 +210,8 @@ def create_version(): log_operation('CREATE_VERSION', 'VERSION', version.version_id, { 'product_id': version.product_id, 'version_num': version.version_num, - 'publish_now': publish_now + 'publish_now': publish_now, + 'has_download_url': bool(download_url) }) return jsonify({ @@ -336,7 +349,10 @@ def update_version_status(version_id): except Exception as e: current_app.logger.error(f"更新版本状态失败: {str(e)}") - return jsonify({'success': False, 'message': '服务器内部错误'}), 500 + return jsonify({ + 'success': False, + 'message': '服务器内部错误' + }), 500 @api_bp.route('/versions/upload', methods=['POST']) @require_login @@ -630,3 +646,13 @@ def batch_update_version_status(): 'message': '服务器内部错误' }), 500 + + + + + + + + + + diff --git a/app/web/templates/version/create.html b/app/web/templates/version/create.html index 8d831f9..81919fb 100644 --- a/app/web/templates/version/create.html +++ b/app/web/templates/version/create.html @@ -50,26 +50,50 @@ - +
- -
-
- - -
未选择文件
+ + +
+ +
+
+ + +
未选择文件
+
+
+
文件名:
+
文件大小:
+
文件哈希:
+ + +
+
支持常见的压缩包和安装包格式
-
-
文件名:
-
文件大小:
-
文件哈希:
- - + + +
-
支持常见的压缩包和安装包格式,文件将单独上传
@@ -241,15 +265,34 @@ function createVersion() { formData.append('update_notes', updateNotes); } - // 添加文件信息(如果已上传) - const fileUrl = document.getElementById('file_url').value; - if (fileUrl) { - formData.append('download_url', fileUrl); - } + // 检查当前选择的文件提供方式 + const activeTab = document.querySelector('.nav-link.active').id; - const fileHash = document.getElementById('file_hash').value; - if (fileHash) { - formData.append('file_hash', fileHash); + if (activeTab === 'upload-tab') { + // 上传文件方式 + const fileUrl = document.getElementById('file_url').value; + if (fileUrl) { + formData.append('download_url', fileUrl); + } + + const fileHash = document.getElementById('file_hash').value; + if (fileHash) { + formData.append('file_hash', fileHash); + } + } else if (activeTab === 'link-tab') { + // 文件链接方式 + const fileLink = document.getElementById('file_link').value.trim(); + if (fileLink) { + formData.append('download_url', fileLink); + } + + // 如果提供了文件名,则使用提供的文件名 + const linkFileName = document.getElementById('link_file_name').value.trim(); + if (linkFileName) { + // 生成一个虚拟的文件哈希(基于文件名) + const fileHash = generateSimpleHash(linkFileName); + formData.append('file_hash', fileHash); + } } const publishNow = document.getElementById('publish_now').checked; @@ -266,6 +309,17 @@ function createVersion() { return; } + // 验证文件提供方式 + if (activeTab === 'upload-tab') { + // 上传方式不需要强制要求文件,但如果有文件则使用 + } else if (activeTab === 'link-tab') { + const fileLink = document.getElementById('file_link').value.trim(); + if (fileLink && !isValidUrl(fileLink)) { + showNotification('请输入有效的文件链接', 'warning'); + return; + } + } + // 显示加载状态 submitBtn.disabled = true; submitText.textContent = '创建中...'; @@ -307,5 +361,26 @@ function createVersion() { submitText.textContent = '创建版本'; }); } + +// 简单的哈希生成函数 +function generateSimpleHash(str) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; // 转换为32位整数 + } + return Math.abs(hash).toString(16); +} + +// 验证URL格式 +function isValidUrl(string) { + try { + new URL(string); + return true; + } catch (_) { + return false; + } +} {% endblock %} \ No newline at end of file diff --git a/instance/kamaxitong.db b/instance/kamaxitong.db index 8a7a98b700f10d78a52b7d13dda8a0c7e3ca9997..51587f7f9566e02d7cd55c9552d167b47a7eb4a2 100644 GIT binary patch delta 79 zcmZoTz}j$tb%Hcw$NeTCz<1Hj{f~w`iLw7#doc8e5rI=$V?EnVXv$85o)B U8XD>vV#qXS%Wcn=W1Q*;0BSQ7nE(I) delta 79 zcmZoTz}j$tb%Hcw`9v9K#`28`TCz+G43m3gw`iLv7@Arc7+M(`>RFf?S{fM{85o)B Y8XD>vqR1GSnj1A|%Wcn=W1Q*;08)Y!7ytkO diff --git a/tests/test_validator.py b/tests/test_validator.py index 95f5130..8e7d652 100644 --- a/tests/test_validator.py +++ b/tests/test_validator.py @@ -74,7 +74,7 @@ class TestAuthValidator(unittest.TestCase): self.software_id = "TEST_SOFTWARE_ID" self.validator = AuthValidator( software_id=self.software_id, - api_url="http://km.taisan.online/api/v1", + api_url="http://127.0.0.1:5000/api/v1", # 使用本地测试URL timeout=1 # 快速超时 )