Files
life-echo/api/app/core/auth_deps.py

54 lines
1.6 KiB
Python
Raw Normal View History

"""Authentication FastAPI dependencies (isolated to avoid circular imports)."""
from typing import Optional
from fastapi import Depends
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_async_db
from app.core.errors import AuthenticationError
from app.core.security import verify_token
from app.features.user.service import UserService
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
oauth2_scheme_optional = OAuth2PasswordBearer(
tokenUrl="/api/auth/login", auto_error=False
)
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_async_db),
):
"""Resolve authenticated user from JWT access token."""
payload = verify_token(token)
if payload is None:
raise AuthenticationError("无法验证凭据")
user_id: str | None = payload.get("sub")
if user_id is None:
raise AuthenticationError("无法验证凭据")
if payload.get("type") != "access":
raise AuthenticationError("无法验证凭据")
user = await UserService(db).get_by_id(user_id)
if user is None:
raise AuthenticationError("无法验证凭据")
return user
async def get_optional_user(
token: Optional[str] = Depends(oauth2_scheme_optional),
db: AsyncSession = Depends(get_async_db),
):
"""Return user if a valid token is provided, else None."""
if token is None:
return None
try:
return await get_current_user(token, db)
except AuthenticationError:
return None