Files
orc-order-v2/web/backend/auth/router.py
T
houhuan dedc3b4183 feat: complete web application — FastAPI backend + Vue 3 SPA frontend
- Full FastAPI backend with JWT auth, file management, processing pipeline,
  memory CRUD, barcode mappings, config management, cloud sync
- Vue 3 + Element Plus frontend with dashboard, task history, HTTP logs,
  memory editor, barcode editor, config editor, sync page
- HTTP request logging middleware with SQLite persistence
- Task history tracking with progress and retry support
- File metadata recording for upload/download operations
- WebAuth section in config.ini for bcrypt password storage
- Bug fix: logs.py count query returns tuple not dict

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 11:59:07 +08:00

90 lines
2.9 KiB
Python

"""Auth API endpoints"""
import os
import bcrypt
from fastapi import APIRouter, HTTPException, Depends, status
from pydantic import BaseModel
from .jwt_handler import create_access_token
from .dependencies import get_current_user
router = APIRouter(prefix="/api/auth", tags=["auth"])
# Default credentials (should be changed on first login)
DEFAULT_USERNAME = "admin"
DEFAULT_PASSWORD = "admin123"
class LoginRequest(BaseModel):
username: str
password: str
class LoginResponse(BaseModel):
access_token: str
token_type: str = "bearer"
def _get_credentials() -> tuple[str, bytes]:
"""Get username and password hash from config or defaults"""
try:
from app.config.settings import ConfigManager
cfg = ConfigManager()
username = cfg.get('WebAuth', 'username', fallback=DEFAULT_USERNAME)
pw_hash = cfg.get('WebAuth', 'password_hash', fallback='')
if not pw_hash:
# First run: store default password hash
pw_hash = bcrypt.hashpw(DEFAULT_PASSWORD.encode(), bcrypt.gensalt()).decode()
try:
cfg.update('WebAuth', 'username', DEFAULT_USERNAME)
cfg.update('WebAuth', 'password_hash', pw_hash)
cfg.save_config()
except Exception:
pass
return username, pw_hash.encode()
except Exception:
return DEFAULT_USERNAME, bcrypt.hashpw(DEFAULT_PASSWORD.encode(), bcrypt.gensalt())
@router.post("/login", response_model=LoginResponse)
async def login(req: LoginRequest):
stored_username, stored_hash = _get_credentials()
if req.username != stored_username:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误")
if not bcrypt.checkpw(req.password.encode(), stored_hash):
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="用户名或密码错误")
token = create_access_token({"sub": req.username})
return LoginResponse(access_token=token)
@router.get("/me")
async def me(current_user: dict = Depends(get_current_user)):
return current_user
class ChangePasswordRequest(BaseModel):
old_password: str
new_password: str
@router.post("/change-password")
async def change_password(req: ChangePasswordRequest, current_user: dict = Depends(get_current_user)):
_, stored_hash = _get_credentials()
if not bcrypt.checkpw(req.old_password.encode(), stored_hash):
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="旧密码错误")
new_hash = bcrypt.hashpw(req.new_password.encode(), bcrypt.gensalt()).decode()
try:
from app.config.settings import ConfigManager
cfg = ConfigManager()
cfg.update('WebAuth', 'password_hash', new_hash)
cfg.save_config()
except Exception as e:
raise HTTPException(status_code=500, detail=f"保存密码失败: {e}")
return {"message": "密码修改成功"}