安全修复和管理员账号密码自定义

This commit is contained in:
2025-12-13 12:37:18 +08:00
parent 7d924bb81e
commit 4606407356
5 changed files with 24 additions and 38 deletions

View File

@@ -86,6 +86,11 @@ async def init_default_config(db: AsyncSession):
"ai_provider": os.getenv("AI_PROVIDER", "openai"),
}
# Validate admin credentials
admin_username = os.getenv("ADMIN_USERNAME", "admin")
if not admin_username or len(admin_username) < 3:
raise ValueError("ADMIN_USERNAME must be at least 3 characters long")
admin_password = os.getenv("ADMIN_PASSWORD")
if not admin_password or len(admin_password) < 12:
raise ValueError("ADMIN_PASSWORD must be set and at least 12 characters long")
@@ -99,15 +104,15 @@ async def init_default_config(db: AsyncSession):
db.add(config)
print(f"✅ Created default config: {key} = {value}")
# Create default admin user if not exists
result = await db.execute(select(User).where(User.username == "admin"))
# Create or update default admin user
result = await db.execute(select(User).where(User.username == admin_username))
admin = result.scalar_one_or_none()
default_admin_id = admin.id if admin else None
if not admin:
admin_user = User(
username="admin",
username=admin_username,
hashed_password=pwd_context.hash(admin_password),
is_admin=True
)
@@ -115,8 +120,12 @@ async def init_default_config(db: AsyncSession):
await db.commit()
await db.refresh(admin_user)
default_admin_id = admin_user.id
print("✅ Created default admin user (username: admin)")
print(f"✅ Created default admin user (username: {admin_username})")
else:
# Update password if it has changed (verify current password doesn't match)
if not pwd_context.verify(admin_password, admin.hashed_password):
admin.hashed_password = pwd_context.hash(admin_password)
print(f"🔄 Updated default admin password (username: {admin_username})")
await db.commit()
if default_admin_id is not None:

View File

@@ -1,7 +1,7 @@
"""
Authentication Router
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, status, Request
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from datetime import timedelta
@@ -66,6 +66,7 @@ async def register(
@router.post("/login", response_model=Token)
@limiter.limit("5/minute")
async def login(
request: Request,
user_data: UserLogin,
db: AsyncSession = Depends(get_db)
):

View File

@@ -1,7 +1,7 @@
"""
Exam Router - Handles exam creation, file upload, and deduplication
"""
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, BackgroundTasks
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, BackgroundTasks, Request
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_
@@ -537,6 +537,7 @@ async def async_parse_and_save(
@router.post("/create", response_model=ExamUploadResponse, status_code=status.HTTP_201_CREATED)
@limiter.limit("10/minute")
async def create_exam_with_upload(
request: Request,
background_tasks: BackgroundTasks,
title: str = Form(...),
file: UploadFile = File(...),
@@ -587,6 +588,7 @@ async def create_exam_with_upload(
@router.post("/{exam_id}/append", response_model=ExamUploadResponse)
@limiter.limit("10/minute")
async def append_document_to_exam(
request: Request,
exam_id: int,
background_tasks: BackgroundTasks,
file: UploadFile = File(...),