"""密码 bcrypt hash;JWT 创建与解码,带过期时间。""" from datetime import datetime, timedelta, timezone from jose import JWTError, jwt from passlib.context import CryptContext from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.models import User pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") def hash_password(password: str) -> str: return pwd_context.hash(password) def verify_password(plain: str, hashed: str) -> bool: return pwd_context.verify(plain, hashed) def create_access_token(subject: str) -> str: expire = datetime.now(timezone.utc) + timedelta(minutes=settings.jwt_expire_minutes) to_encode = {"sub": subject, "exp": expire} return jwt.encode(to_encode, settings.jwt_secret, algorithm=settings.jwt_algorithm) def decode_access_token(token: str) -> str | None: try: payload = jwt.decode(token, settings.jwt_secret, algorithms=[settings.jwt_algorithm]) return payload.get("sub") except JWTError: return None async def get_user_by_username(db: AsyncSession, username: str) -> User | None: r = await db.execute(select(User).where(User.username == username)) return r.scalar_one_or_none()