import os from datetime import datetime, timedelta, timezone from typing import Optional import bcrypt from fastapi import Depends, HTTPException, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from jose import JWTError, jwt from sqlalchemy.orm import Session from database import get_db from models import User SECRET_KEY = os.getenv("WORDLOOP_SECRET_KEY", "wordloop-dev-secret-change-in-production") ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24 * 7 security = HTTPBearer() def hash_password(password: str) -> str: return bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") def verify_password(plain: str, hashed: str) -> bool: return bcrypt.checkpw(plain.encode("utf-8"), hashed.encode("utf-8")) def create_access_token(user_id: int, username: str) -> str: expire = datetime.now(timezone.utc) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) payload = {"sub": str(user_id), "username": username, "exp": expire} return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) def get_current_user( credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db), ) -> User: token = credentials.credentials credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="无效或过期的登录凭证", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) user_id: Optional[str] = payload.get("sub") if user_id is None: raise credentials_exception except JWTError: raise credentials_exception user = db.query(User).filter(User.id == int(user_id)).first() if user is None: raise credentials_exception return user