from datetime import datetime, timedelta, timezone from typing import Any, Dict, Optional from fastapi import HTTPException, status from fastapi.security import OAuth2PasswordBearer from jose import JWTError, jwt from passlib.context import CryptContext from app.core.config import settings ALGORITHM = "HS256" pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login", scheme_name="Bearer") def create_access_token(*, user_id: str, role: str, expires_minutes: Optional[int] = None) -> str: expire = datetime.now(timezone.utc) + timedelta( minutes=expires_minutes or settings.JWT_EXPIRE_MINUTES ) to_encode: Dict[str, Any] = {"sub": user_id, "role": role, "exp": expire} return jwt.encode(to_encode, settings.JWT_SECRET_KEY, algorithm=ALGORITHM) def decode_token(token: str) -> Dict[str, Any]: try: payload = jwt.decode(token, settings.JWT_SECRET_KEY, algorithms=[ALGORITHM]) except JWTError as exc: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无法验证登录凭据", headers={"WWW-Authenticate": "Bearer"}, ) from exc return payload def hash_password(plain_password: str) -> str: return pwd_context.hash(plain_password) def verify_password(plain_password: str, hashed_password: str) -> bool: return pwd_context.verify(plain_password, hashed_password)