Step 2:用户 CRUD + bcrypt + JWT 真实鉴权 + RBAC 依赖

This commit is contained in:
Cheng Zhou
2025-12-16 16:15:28 +08:00
parent 223d445a94
commit 65df698570
44 changed files with 215 additions and 33 deletions
+24 -11
View File
@@ -1,11 +1,11 @@
from datetime import timedelta
from fastapi import APIRouter, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.config import settings
from app.core.security import create_access_token
from app.schemas.user import Token
from app.core.security import create_access_token, verify_password
from app.core.deps import get_current_user, get_db_session
from app.crud import user as user_crud
from app.schemas.user import Token, UserRead
class LoginRequest(BaseModel):
@@ -17,16 +17,29 @@ router = APIRouter()
@router.post("/login", response_model=Token)
async def login_for_access_token(payload: LoginRequest) -> Token:
if not (payload.username == "admin" and payload.password == "admin"):
async def login_for_access_token(
payload: LoginRequest, db: AsyncSession = Depends(get_db_session)
) -> Token:
db_user = await user_crud.get_by_username(db, payload.username)
if not db_user or not verify_password(payload.password, db_user.hashed_password):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
)
if not db_user.is_active:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Inactive user",
)
access_token = create_access_token(
subject="00000000-0000-0000-0000-000000000001",
role="PM",
expires_delta=timedelta(minutes=settings.JWT_EXPIRE_MINUTES),
user_id=str(db_user.id),
role=db_user.role,
expires_minutes=None,
)
return Token(access_token=access_token, token_type="bearer")
@router.get("/me", response_model=UserRead)
async def read_me(current_user=Depends(get_current_user)) -> UserRead:
return current_user
+2 -1
View File
@@ -1,6 +1,7 @@
from fastapi import APIRouter
from app.api.v1 import auth
from app.api.v1 import auth, users
api_router = APIRouter()
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
api_router.include_router(users.router, prefix="/users", tags=["users"])
+51
View File
@@ -0,0 +1,51 @@
import uuid
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_db_session, require_roles
from app.crud import user as user_crud
from app.schemas.user import UserCreate, UserRead, UserUpdate
router = APIRouter()
@router.get("/", response_model=list[UserRead])
async def list_users(
skip: int = 0,
limit: int = 100,
db: AsyncSession = Depends(get_db_session),
current_user=Depends(require_roles(["ADMIN"])),
) -> list[UserRead]:
users = await user_crud.list_users(db, skip=skip, limit=limit)
return list(users)
@router.post("/", response_model=UserRead, status_code=status.HTTP_201_CREATED)
async def create_user(
user_in: UserCreate,
db: AsyncSession = Depends(get_db_session),
current_user=Depends(require_roles(["ADMIN"])),
) -> UserRead:
existing = await user_crud.get_by_username(db, user_in.username)
if existing:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Username already exists",
)
user = await user_crud.create_user(db, user_in)
return user
@router.patch("/{user_id}", response_model=UserRead)
async def update_user(
user_id: uuid.UUID,
user_in: UserUpdate,
db: AsyncSession = Depends(get_db_session),
current_user=Depends(require_roles(["ADMIN"])),
) -> UserRead:
db_user = await user_crud.get_by_id(db, user_id)
if not db_user:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
user = await user_crud.update_user(db, db_user, user_in)
return user