Files
video-gen/video-gen-api/app/services/auth.py
T
2026-05-25 17:08:18 +08:00

52 lines
1.7 KiB
Python

from datetime import datetime, timedelta, timezone
import bcrypt
import jwt
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
from app.models.user import User
def hash_password(plain: str) -> str:
return bcrypt.hashpw(plain.encode(), bcrypt.gensalt()).decode()
def verify_password(plain: str, hashed: str) -> bool:
return bcrypt.checkpw(plain.encode(), hashed.encode())
def create_access_token(user_id: str, remember_me: bool = False) -> str:
minutes = settings.JWT_EXPIRE_REMEMBER_MINUTES if remember_me else settings.JWT_EXPIRE_MINUTES
expire = datetime.now(timezone.utc) + timedelta(minutes=minutes)
payload = {"sub": user_id, "exp": expire}
return jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
def decode_access_token(token: str) -> str | None:
"""Decode JWT and return user_id, or None if invalid."""
try:
payload = jwt.decode(
token, settings.SECRET_KEY, algorithms=[settings.JWT_ALGORITHM]
)
return payload.get("sub")
except jwt.PyJWTError:
return None
async def authenticate_user(
db: AsyncSession, username: str, password: str
) -> User | None:
result = await db.execute(select(User).where(User.username == username))
user = result.scalar_one_or_none()
if not user:
# Try phone number lookup for frontend users
result = await db.execute(select(User).where(User.phone == username))
user = result.scalar_one_or_none()
if not user or not verify_password(password, user.hashed_password):
return None
if not user.is_active:
return None
return user