geo/backend/app/services/auth.py

69 lines
1.9 KiB
Python

import uuid
from datetime import datetime, timedelta, timezone
from jose import jwt, JWTError
from passlib.context import CryptContext
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
from app.models.user import User
from app.schemas.auth import UserRegister
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
def create_access_token(data: dict) -> str:
to_encode = data.copy()
expire = datetime.now(timezone.utc) + timedelta(hours=settings.JWT_EXPIRE_HOURS)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET, algorithm="HS256")
return encoded_jwt
def verify_token(token: str) -> dict:
payload = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"])
return payload
async def register_user(db: AsyncSession, user_data: UserRegister) -> User:
stmt = select(User).where(User.email == user_data.email)
result = await db.execute(stmt)
existing_user = result.scalar_one_or_none()
if existing_user:
raise ValueError("邮箱已被注册")
user = User(
email=user_data.email,
password_hash=hash_password(user_data.password),
name=user_data.name,
)
db.add(user)
await db.commit()
await db.refresh(user)
return user
async def authenticate_user(
db: AsyncSession, email: str, password: str
) -> User | None:
stmt = select(User).where(User.email == email)
result = await db.execute(stmt)
user = result.scalar_one_or_none()
if not user:
return None
if not verify_password(password, user.password_hash):
return None
return user