Add 'backend/' from commit '48a644fb354d6c6efcbd12bc1b4a2cb83137b68e'

git-subtree-dir: backend
git-subtree-mainline: 545699d16f
git-subtree-split: 48a644fb35
This commit is contained in:
carry
2025-02-17 17:44:42 +08:00
15 changed files with 699 additions and 0 deletions

32
backend/routes/auth.py Normal file
View File

@@ -0,0 +1,32 @@
from fastapi import APIRouter, Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from schemas.auth import TokenResponse, LoginRequest, RefreshTokenRequest
from services.auth import create_tokens_response, refresh_tokens
from services.user import authenticate_user
from services.db import get_db_session_dep
router = APIRouter(tags=["auth"])
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@router.post("/login", response_model=TokenResponse)
async def login(
login_data: LoginRequest,
session: AsyncSession = Depends(get_db_session_dep)
):
user = await authenticate_user(session, login_data.username, login_data.password)
if not user:
raise HTTPException(
status_code=401,
detail="Invalid username or password",
headers={"WWW-Authenticate": "Bearer"},
)
return create_tokens_response(user.id, user.username, user.role)
@router.post("/refresh", response_model=TokenResponse)
async def refresh_token(refresh_data: RefreshTokenRequest):
tokens = refresh_tokens(refresh_data.refresh_token)
if not tokens:
raise HTTPException(status_code=401, detail="Invalid refresh token")
return tokens

34
backend/routes/depends.py Normal file
View File

@@ -0,0 +1,34 @@
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from typing import Optional
from schemas.auth import TokenPayload
from schemas.user import UserRole
from services.auth import verify_access_token
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/login")
async def _get_token_data(token: str) -> TokenPayload:
"""验证并返回TokenData"""
token_data = verify_access_token(token)
if token_data is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return token_data
async def get_current_user(token: str = Depends(oauth2_scheme)) -> TokenPayload:
"""获取当前用户"""
return await _get_token_data(token)
async def get_current_admin(token: str = Depends(oauth2_scheme)) -> TokenPayload:
"""获取当前管理员用户"""
token_data = await _get_token_data(token)
if token_data.role not in [UserRole.SYSTEM_ADMIN, UserRole.ADMIN]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied: Insufficient privileges for this operation",
headers={"WWW-Authenticate": "Bearer"},
)
return token_data

69
backend/routes/users.py Normal file
View File

@@ -0,0 +1,69 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List, Optional
from schemas.auth import TokenPayload
from schemas.user import UserCreate, UserUpdate, UserResponse, UserRole
from routes.depends import get_current_user,get_current_admin
import services.user as user_service
from services.db import get_db_session_dep
router = APIRouter(tags=["users"])
@router.get("/", response_model=List[UserResponse])
async def get_users_list(
page: int = 1,
limit: int = 100,
role: Optional[str] = None,
current_user_token: TokenPayload = Depends(get_current_user),
session: AsyncSession = Depends(get_db_session_dep)
):
skip = (page - 1) * limit
users = await user_service.get_users_list(session, skip=skip, limit=limit)
if role:
users = [user for user in users if user.role == role]
return users
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(
user_data: UserCreate,
current_user_token: TokenPayload = Depends(get_current_admin),
session: AsyncSession = Depends(get_db_session_dep)
):
return await user_service.create_user(session, user_data)
@router.put("/{user_id}", response_model=UserResponse)
async def update_user(
user_id: int,
user_data: UserUpdate,
current_user_token: TokenPayload = Depends(get_current_admin),
session: AsyncSession = Depends(get_db_session_dep)
):
return await user_service.update_user(session, user_id, user_data)
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(
user_id: int,
current_user_token: TokenPayload = Depends(get_current_user),
session: AsyncSession = Depends(get_db_session_dep)
):
user = await user_service.get_user(session, user_id)
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found"
)
return user
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
user_id: int,
current_user_token: TokenPayload = Depends(get_current_admin),
session: AsyncSession = Depends(get_db_session_dep)
):
success = await user_service.delete_user(session, user_id)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found"
)