""" 认证 API 端点 """ from fastapi import APIRouter, HTTPException, status from pydantic import BaseModel, EmailStr from typing import Optional from datetime import datetime, timedelta import secrets router = APIRouter() # 模拟用户数据库 MOCK_USERS = { "agency@test.com": { "user_id": "user_agency_001", "email": "agency@test.com", "password": "password", "role": "agency", "appeal_tokens": 5, }, "creator@test.com": { "user_id": "user_creator_001", "email": "creator@test.com", "password": "password", "role": "creator", "appeal_tokens": 3, }, "reviewer@test.com": { "user_id": "user_reviewer_001", "email": "reviewer@test.com", "password": "password", "role": "reviewer", "appeal_tokens": 0, }, "brand@test.com": { "user_id": "user_brand_001", "email": "brand@test.com", "password": "password", "role": "brand", "appeal_tokens": 0, }, "no_token@test.com": { "user_id": "user_no_token_001", "email": "no_token@test.com", "password": "password", "role": "creator", "appeal_tokens": 0, }, } # 模拟 token 存储 TOKENS: dict[str, dict] = {} class LoginRequest(BaseModel): email: EmailStr password: str class LoginResponse(BaseModel): access_token: str token_type: str = "bearer" user_id: str role: str expires_in: int = 3600 class UserProfile(BaseModel): user_id: str email: str role: str appeal_tokens: int @router.post("/login", response_model=LoginResponse) async def login(request: LoginRequest): """用户登录""" user = MOCK_USERS.get(request.email) if not user or user["password"] != request.password: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid email or password", ) # 生成 token token = secrets.token_urlsafe(32) TOKENS[token] = { "user_id": user["user_id"], "email": user["email"], "role": user["role"], "expires_at": datetime.now() + timedelta(hours=1), } return LoginResponse( access_token=token, user_id=user["user_id"], role=user["role"], ) def get_current_user(token: str) -> dict: """验证 token 并返回用户信息""" if not token or not token.startswith("Bearer "): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authorization header", ) token_value = token[7:] # 移除 "Bearer " 前缀 token_data = TOKENS.get(token_value) if not token_data: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token", ) if datetime.now() > token_data["expires_at"]: del TOKENS[token_value] raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired", ) return token_data def get_user_by_id(user_id: str) -> dict | None: """根据 user_id 获取用户""" for email, user in MOCK_USERS.items(): if user["user_id"] == user_id: return user return None def update_user_tokens(user_id: str, delta: int) -> None: """更新用户申诉令牌""" for email, user in MOCK_USERS.items(): if user["user_id"] == user_id: user["appeal_tokens"] += delta break