refactor: P6 API v1 版本化

- src/routes/v1.py:注册中心,148 条路由全部挂 /api/v1
- application/views/__init__.py:自动发现改为 register_v1 显式注册
- 登录白名单更新为 /api/v1/login 等(.env 与 .env.example)
- build_full_url:内部调度调用自动加 /api/v1 前缀

【联动】ui/ 前端需将 API 调用前缀改为 /api/v1(随 ui/ 迁移处理)
【验收】148 路由全 /api/v1;白名单放行(/api/v1/login 表单校验);
鉴权拦截 401;build_full_url 验证;12 passed

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 19:42:05 +08:00
co-authored by Claude
parent 4b0b28105c
commit 4d74b31431
6 changed files with 74 additions and 29 deletions
+3 -3
View File
@@ -76,9 +76,9 @@ INTERNAL_API_KEY=<必填>
INTERNAL_ALLOWED_IPS=127.0.0.1
# 登录白名单(以下路径跳过登录校验)
LOGIN_WHITELIST_EXACT=/login,/captcha,/favicon.ico
LOGIN_WHITELIST_PREFIX=/job/sendSms,/public,/static,/api/webhook
LOGIN_WHITELIST_WILDCARD=/job/*/send*,/api/v1/*/public*
LOGIN_WHITELIST_EXACT=/api/v1/login,/api/v1/captcha,/favicon.ico
LOGIN_WHITELIST_PREFIX=/api/v1/job/sendSms,/public,/static,/api/webhook
LOGIN_WHITELIST_WILDCARD=/api/v1/job/*/send*,/api/v1/*/public*
LOGIN_WHITELIST_DEBUG=True
LOGIN_WHITELIST_LOG_ACCESS=True
+5 -25
View File
@@ -102,36 +102,16 @@ _blueprint_modules = [
def register_blueprint(app):
"""
自动导入所有视图模块并注册蓝图到Flask应用实例
注册 API v1 路由到 Flask 应用实例
功能说明:
遍历 _blueprint_modules 列表,动态导入每个视图模块,
自动发现模块中的 Blueprint 实例并注册到应用。
此函数在应用启动时调用(通常位于 create_app 工厂函数中)。
所有业务蓝图统一挂载到 /api/v1 前缀(见 src/routes/v1.py)。
原自动发现机制已由 routes/v1.py 的显式注册取代。
Args:
app: Flask应用实例
Returns:
Flask: 注册完成后的Flask应用实例
Example:
# 在应用工厂函数中调用
def create_app():
app = Flask(__name__)
# ... 其他配置 ...
register_blueprint(app)
return app
"""
registered = set()
for module_name in _blueprint_modules:
mod = importlib.import_module(f'application.views.{module_name}')
for attr_name in dir(mod):
attr = getattr(mod, attr_name)
if isinstance(attr, Blueprint):
# 合并模块的 shim 会重复导出同一批 Blueprint,按名去重
if attr.name in registered:
continue
app.register_blueprint(attr)
registered.add(attr.name)
return app
from src.routes.v1 import register_v1
return register_v1(app)
+3
View File
@@ -132,6 +132,9 @@ def build_full_url(url: str) -> str:
# 相对路径,拼接站点域名
if url.startswith("/"):
# 内部 API 调用统一挂到 /api/v1(P6 API 版本化)
if not url.startswith("/api/"):
url = f"/api/v1{url}"
url = f"{FLASK_SITE_DOMAIN}{url}"
return url
+1
View File
@@ -0,0 +1 @@
"""路由注册中心包。"""
+61
View File
@@ -0,0 +1,61 @@
"""
API v1 路由注册中心
=============================================================
所有业务蓝图统一挂载到 /api/v1 前缀下:
- 模块内蓝图保持各自的 url_prefix(如 /user、/role)
- 整体前缀由 v1 父蓝图提供 → /api/v1/user/page 等
联动说明:
- 登录白名单需改为 /api/v1/login 等(见 config/auth.py 与 .env)
- 内部 HTTP 调用(定时任务)需追加 /api/v1
"""
from flask import Blueprint
from src.modules.auth.router import login_blue, index_blue
from src.modules.association.role_menu.router import role_menu_blue
from src.modules.association.user_role.router import user_role_blue
from src.modules.city.router import city_blue
from src.modules.cms.article.router import article_blue
from src.modules.cms.category.router import category_blue
from src.modules.cms.link.router import link_blue
from src.modules.configuration.router import config_blue, config_item_blue
from src.modules.dictionary.router import dict_blue, dict_item_blue
from src.modules.file_template.router import file_template_blue
from src.modules.job.router import job_blue
from src.modules.log.router import login_log_blue, operation_log_blue
from src.modules.notice.router import notice_blue
from src.modules.param.router import param_blue
from src.modules.system.dept.router import dept_blue
from src.modules.system.level.router import level_blue
from src.modules.system.menu.router import menu_blue
from src.modules.system.position.router import position_blue
from src.modules.system.role.router import role_blue
from src.modules.system.user.router import user_blue
from src.modules.upload.router import upload_blue
# 全部业务蓝图(按领域分组排序)
BLUEPRINTS = [
login_blue, index_blue,
user_blue, role_blue, menu_blue, dept_blue, position_blue, level_blue,
user_role_blue, role_menu_blue,
dict_blue, dict_item_blue, config_blue, config_item_blue,
param_blue, notice_blue, category_blue, article_blue, link_blue,
upload_blue, file_template_blue, login_log_blue, operation_log_blue,
city_blue, job_blue,
]
def register_v1(app):
"""
注册 API v1 路由(所有业务蓝图挂载到 /api/v1)。
Args:
app: Flask 应用实例
"""
v1 = Blueprint('v1', __name__, url_prefix='/api/v1')
for blue in BLUEPRINTS:
v1.register_blueprint(blue)
app.register_blueprint(v1)
return app
+1 -1
View File
@@ -356,7 +356,7 @@ from src.core.database import db # 统一 db 单例
| **P3 模块搬迁** | 按 §2.5 顺序逐组迁移 23 个模块(models→forms→services→views),每批打 shim + 验证 | 已验收:22 模型→19 模块 models.py;23 表单→schema.py;29 服务→service.py(含 executor/scheduler_service/mail_service/sms_service);26 视图→router.py(login+index 合并入 auth)。应用启动、25 蓝图无重复注册(views/__init__.py 已加去重)、pytest 5 passed、接口冒烟(登录校验/鉴权 401)正常 | 中(已完成) |
| **P4 服务层改造** | 26 个服务文件改「入参数据/出参数据」;router 取参包 R;引入 base_service/base_repository + BizError | **✅ 全部完成(21 模块)**:P4a 地基、P4b position 标杆(含单测)、P4c 六个批次(notice/param/link/level、article/category/file_template、dept/city、role/menu/user_role/role_menu、log/dictionary/configuration、job/auth/user)。每模块 flake8 零告警 + 应用启动 + 运行时验证。**合并模块已修复重名函数覆盖/双 import 块/路由导入 bug**。注:level 的 Excel import/export 仍返回 R(暂保留,后续统一改造) | 高(全部完成) |
| **P5 DI 注入** | core/permission.py + op_log 接口化;app 工厂注入 menu 服务 | **✅ 已完成**:PermissionProvider 协议 + check_permission 去 menu 依赖;core/middleware.py 整合全部中间件;factory 注入 MenuPermissionProvider + record_operation_log;src/core 零 application 引用;权限/日志行为一致;flake8 零告警 | 中(已完成) |
| **P6 API v1** | routes/v1.py + `/api/v1`;白名单/内部调用/前端前缀同步 | 全部接口路径 `curl /api/v1/...` 通过;`/login` 白名单放行 | 中 |
| **P6 API v1** | routes/v1.py + `/api/v1`;白名单/内部调用/前端前缀同步 | **✅ 已完成**:148 条路由全部挂 /api/v1;白名单已更新(/api/v1/login 等);build_full_url 内部调用自动加前缀;冒烟验证通过。**前端联动**:ui/ 需将 API 调用前缀改为 /api/v1(待 ui/ 迁移时一并处理) | 中(已完成) |
| **P7 切尾** | 删除 application/extensions/utils;`src/wsgi.py`;gunicorn.conf 指向 src.wsgi;更新 CLAUDE.md | `gunicorn -c gunicorn.conf.py src.wsgi:app` 启动;全量回归 | 高 |
| **P8 测试+文档** | tests/ 全量落地;CHANGELOG / CONTRIBUTING / API 文档 | `pytest` 通过;覆盖率报告 | 低 |
| **P9 运维** | Docker 修复(§2.7)+ CI/CD(lint→type-check→pytest→build) | `docker-compose up -d` 健康检查通过 | 低 |