from fastapi import APIRouter, Depends, HTTPException, Request, status from jose import JWTError from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.services.admin_service import get_system_configs from app.schemas.auth import TokenRefreshRequest, WxLoginRequest, WxLoginResponse from app.services.auth_service import login_with_wechat from app.utils.rate_limit import client_ip, enforce_rate_limit from app.utils.security import create_access_token, decode_access_token router = APIRouter() @router.get("/public-config") async def public_config(session: AsyncSession = Depends(get_db)) -> dict: configs = await get_system_configs(session) return { "code": 0, "message": "ok", "data": { "api_base_url": configs.get("api_base_url") or "http://127.0.0.1:8000/api/v1", "customer_service_wechat": configs.get("customer_service_wechat") or "service_wechat_001", }, } @router.post("/wx-login") async def wx_login( payload: WxLoginRequest, request: Request, session: AsyncSession = Depends(get_db), ) -> dict: await enforce_rate_limit( key=f"rate:login:{client_ip(request)}", limit=10, window_seconds=60, message="登录过于频繁,请稍后再试", ) try: result = await login_with_wechat(session, payload) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc data = WxLoginResponse(**result) return {"code": 0, "message": "ok", "data": data.model_dump()} @router.post("/refresh") async def refresh_token(payload: TokenRefreshRequest) -> dict: try: token_payload = decode_access_token(payload.refresh_token) except JWTError as exc: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="刷新令牌无效或已过期") from exc if token_payload.get("token_type") != "refresh": raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="刷新令牌无效") user_id = token_payload.get("user_id") if not user_id: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="刷新令牌无效") token = create_access_token({"user_id": user_id, "token_type": "access"}) return { "code": 0, "message": "ok", "data": { "access_token": token, "token_type": "bearer", "expires_in": 7200, "user_id": int(user_id), }, }