From ef24868105b5962b1df3e373b694a0d349f79796 Mon Sep 17 00:00:00 2001 From: Nelson <1475262689@qq.com> Date: Thu, 9 Jul 2026 16:45:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E5=90=8E=E5=8F=B0?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=BB=98=E8=AE=A4=E5=87=AD=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apps/admin-web/src/App.vue | 7 +-- .../apps/backend/.env.example | 1 + .../apps/backend/app/core/config.py | 4 +- .../backend/app/services/admin_service.py | 46 +++++++++++++++++-- ai_knowledge_base_v2/docker-compose.dev.yml | 5 +- 5 files changed, 53 insertions(+), 10 deletions(-) diff --git a/ai_knowledge_base_v2/apps/admin-web/src/App.vue b/ai_knowledge_base_v2/apps/admin-web/src/App.vue index 7507af5..67d5f0f 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/App.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/App.vue @@ -21,7 +21,7 @@ const admin = ref(null); const activeMenu = ref("dashboard"); const loading = ref(false); -const loginForm = reactive({ username: "admin", password: "admin123456" }); +const loginForm = reactive({ username: "", password: "" }); const stats = ref(null); const dashboardFilters = reactive({ start: "", @@ -1068,9 +1068,9 @@ function formatRecordDateTime(value: string, boundary: "start" | "end") {

登录答疑后台

请输入大本营答疑助手后台管理员账号和密码。

- + - + diff --git a/ai_knowledge_base_v2/apps/backend/.env.example b/ai_knowledge_base_v2/apps/backend/.env.example index 608d949..221c902 100644 --- a/ai_knowledge_base_v2/apps/backend/.env.example +++ b/ai_knowledge_base_v2/apps/backend/.env.example @@ -40,6 +40,7 @@ CHAT_MAX_QUEUE_SIZE=20 CHAT_QUEUE_TIMEOUT_SECONDS=60 CHAT_ACTIVE_LEASE_SECONDS=900 +# 本地开发可以使用开发密码;生产环境必须改成高强度密码,且 APP_ENV=production 时不能使用 admin123456 BOOTSTRAP_ADMIN_USERNAME=admin BOOTSTRAP_ADMIN_PASSWORD=admin123456 BOOTSTRAP_ADMIN_NAME=系统管理员 diff --git a/ai_knowledge_base_v2/apps/backend/app/core/config.py b/ai_knowledge_base_v2/apps/backend/app/core/config.py index 6bccad6..9ece30c 100644 --- a/ai_knowledge_base_v2/apps/backend/app/core/config.py +++ b/ai_knowledge_base_v2/apps/backend/app/core/config.py @@ -60,8 +60,8 @@ class Settings(BaseSettings): chat_max_queue_size: int = 20 chat_queue_timeout_seconds: int = 60 chat_active_lease_seconds: int = 900 - bootstrap_admin_username: str = "admin" - bootstrap_admin_password: str = "admin123456" + bootstrap_admin_username: str = "" + bootstrap_admin_password: str = "" bootstrap_admin_name: str = "系统管理员" diff --git a/ai_knowledge_base_v2/apps/backend/app/services/admin_service.py b/ai_knowledge_base_v2/apps/backend/app/services/admin_service.py index 52b422c..8c4330c 100644 --- a/ai_knowledge_base_v2/apps/backend/app/services/admin_service.py +++ b/ai_knowledge_base_v2/apps/backend/app/services/admin_service.py @@ -15,6 +15,44 @@ from app.models.logs import AiRequestLog, OperationLog from app.models.user import User +DEVELOPMENT_ENVS = {"local", "dev", "development", "docker", "test", "testing"} +UNSAFE_BOOTSTRAP_PASSWORDS = { + "123456", + "admin", + "admin123456", + "change-me-in-production", + "password", + "replace-with-strong-password", +} + + +def _is_production_env(app_env: str) -> bool: + return app_env.strip().lower() not in DEVELOPMENT_ENVS + + +def _get_bootstrap_admin_config() -> tuple[str, str, str]: + settings = get_settings() + username = settings.bootstrap_admin_username.strip() + password = settings.bootstrap_admin_password + name = settings.bootstrap_admin_name.strip() or username + + if not username or not password: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="未配置首个管理员初始化账号,请配置 BOOTSTRAP_ADMIN_USERNAME/BOOTSTRAP_ADMIN_PASSWORD", + ) + + if _is_production_env(settings.app_env): + normalized_password = password.strip().lower() + if normalized_password in UNSAFE_BOOTSTRAP_PASSWORDS or len(password) < 12: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="生产环境首个管理员初始化密码不安全,请重新配置 BOOTSTRAP_ADMIN_PASSWORD", + ) + + return username, password, name + + class AdminAuthService: @classmethod def login(cls, db: Session, username: str, password: str) -> dict: @@ -47,11 +85,11 @@ class AdminAuthService: has_admin = db.scalar(select(func.count(Admin.id))) or 0 if has_admin: return - settings = get_settings() + username, password, name = _get_bootstrap_admin_config() admin = Admin( - username=settings.bootstrap_admin_username, - password=hash_password(settings.bootstrap_admin_password), - name=settings.bootstrap_admin_name, + username=username, + password=hash_password(password), + name=name, status=1, ) db.add(admin) diff --git a/ai_knowledge_base_v2/docker-compose.dev.yml b/ai_knowledge_base_v2/docker-compose.dev.yml index b58d94e..c27a3fc 100644 --- a/ai_knowledge_base_v2/docker-compose.dev.yml +++ b/ai_knowledge_base_v2/docker-compose.dev.yml @@ -40,7 +40,7 @@ services: context: ./apps/backend container_name: ai_kb_v2_backend environment: - APP_ENV: docker + APP_ENV: ${APP_ENV:-docker} DEBUG: "true" DATABASE_URL: mysql+pymysql://ai_kb:ai_kb@mysql:3306/ai_knowledge_base_v2?charset=utf8mb4 REDIS_URL: redis://redis:6379/0 @@ -58,6 +58,9 @@ services: FEISHU_SEARCH_URL: "${FEISHU_SEARCH_URL:-}" FEISHU_APP_ID: "${FEISHU_APP_ID:-}" FEISHU_APP_SECRET: "${FEISHU_APP_SECRET:-}" + BOOTSTRAP_ADMIN_USERNAME: ${BOOTSTRAP_ADMIN_USERNAME:-admin} + BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-admin123456} + BOOTSTRAP_ADMIN_NAME: ${BOOTSTRAP_ADMIN_NAME:-系统管理员} AUTO_CREATE_TABLES: "false" ports: - "8100:8100"