Files
loom/backend/app/services/auth_service.py
T
2026-04-24 17:46:03 +08:00

61 lines
2.1 KiB
Python

"""登录 / Token 刷新业务逻辑。"""
from __future__ import annotations
from fastapi import status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.exceptions import AppError
from app.core.security import (
JWTError,
create_access_token,
create_refresh_token,
decode_token,
verify_password,
)
from app.models import User
from app.schemas.auth import TokenPair
from app.core.config import settings
async def login(db: AsyncSession, username: str, password: str) -> tuple[User, TokenPair]:
stmt = select(User).where(User.username == username)
user = (await db.execute(stmt)).scalar_one_or_none()
if user is None or not verify_password(password, user.password_hash):
raise AppError("账号或密码错误", code=401, http_status=status.HTTP_401_UNAUTHORIZED)
if user.status != "ACTIVE":
raise AppError("账号已禁用", code=403, http_status=status.HTTP_403_FORBIDDEN)
access = create_access_token(user.id)
refresh = create_refresh_token(user.id)
return user, TokenPair(
access_token=access,
refresh_token=refresh,
expires_in=settings.JWT_ACCESS_TTL,
)
async def refresh(db: AsyncSession, refresh_token: str) -> TokenPair:
try:
payload = decode_token(refresh_token)
except JWTError as e:
raise AppError(
"refresh_token 无效", code=401, http_status=status.HTTP_401_UNAUTHORIZED
) from e
if payload.get("type") != "refresh":
raise AppError("token 类型错误", code=401, http_status=status.HTTP_401_UNAUTHORIZED)
try:
user_id = int(payload["sub"])
except (KeyError, ValueError) as e:
raise AppError("token 无效", code=401, http_status=status.HTTP_401_UNAUTHORIZED) from e
user = await db.get(User, user_id)
if user is None or user.status != "ACTIVE":
raise AppError("账号已失效", code=401, http_status=status.HTTP_401_UNAUTHORIZED)
return TokenPair(
access_token=create_access_token(user.id),
refresh_token=create_refresh_token(user.id),
expires_in=settings.JWT_ACCESS_TTL,
)