49 lines
1.5 KiB
Python
49 lines
1.5 KiB
Python
"""认证 API"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from fastapi.security import OAuth2PasswordRequestForm
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy.future import select
|
|
|
|
from ..core.database import get_db
|
|
from ..models import User, UserStatus
|
|
from ..schemas import UserLoginResponse
|
|
from ..services.auth import AuthService
|
|
|
|
router = APIRouter(prefix="/auth", tags=["auth"])
|
|
|
|
|
|
@router.post("/login", response_model=UserLoginResponse)
|
|
async def login(
|
|
credentials: OAuth2PasswordRequestForm = Depends(),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""用户登录,返回 JWT"""
|
|
result = await db.execute(
|
|
select(User).where(User.username == credentials.username)
|
|
)
|
|
user = result.scalar_one_or_none()
|
|
|
|
if not user or not AuthService.verify_password(
|
|
credentials.password, user.password_hash
|
|
):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
detail="Incorrect username or password",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
|
|
if not getattr(user, "is_active", True) or user.status != UserStatus.ACTIVE.value:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
detail="User is disabled",
|
|
)
|
|
|
|
access_token = AuthService.create_access_token(data={"sub": user.username})
|
|
|
|
return UserLoginResponse(
|
|
access_token=access_token,
|
|
token_type="bearer",
|
|
user=user.to_dict(),
|
|
)
|