64 lines
2.0 KiB
Python
64 lines
2.0 KiB
Python
"""认证接口:注册、登录、当前用户。"""
|
|
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
|
from fastapi.security import OAuth2PasswordRequestForm
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.db import get_db
|
|
from app.deps import get_current_user
|
|
from app.models.user import User
|
|
from app.ratelimit import AUTH_LIMIT, limiter
|
|
from app.schemas.auth import RegisterRequest, Token, UserOut
|
|
from app.services.security import (
|
|
create_access_token,
|
|
hash_password,
|
|
verify_password,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
|
|
|
|
|
@router.post("/register", response_model=UserOut, status_code=status.HTTP_201_CREATED)
|
|
@limiter.limit(AUTH_LIMIT)
|
|
async def register(
|
|
request: Request,
|
|
payload: RegisterRequest,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
exists = await db.scalar(select(User).where(User.username == payload.username))
|
|
if exists:
|
|
raise HTTPException(status.HTTP_409_CONFLICT, detail="用户名已存在")
|
|
user = User(
|
|
username=payload.username,
|
|
email=payload.email,
|
|
password_hash=hash_password(payload.password),
|
|
)
|
|
db.add(user)
|
|
await db.commit()
|
|
await db.refresh(user)
|
|
return user
|
|
|
|
|
|
@router.post("/login", response_model=Token)
|
|
@limiter.limit(AUTH_LIMIT)
|
|
async def login(
|
|
request: Request,
|
|
form: OAuth2PasswordRequestForm = Depends(),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
user = await db.scalar(select(User).where(User.username == form.username))
|
|
if not user or not verify_password(form.password, user.password_hash):
|
|
raise HTTPException(
|
|
status.HTTP_401_UNAUTHORIZED,
|
|
detail="用户名或密码错误",
|
|
headers={"WWW-Authenticate": "Bearer"},
|
|
)
|
|
if not user.is_active:
|
|
raise HTTPException(status.HTTP_403_FORBIDDEN, detail="账户已禁用")
|
|
return Token(access_token=create_access_token(user.id))
|
|
|
|
|
|
@router.get("/me", response_model=UserOut)
|
|
async def me(current: User = Depends(get_current_user)):
|
|
return current
|