
FastAPI
Learn the fundamentals of role based access in FastAPI.
Role-Based Access Control (RBAC) allows you to grant permissions based on user roles. Different roles have different permissions, enabling fine-grained authorization in your API.
In this section, you'll understand:
from typing import List
from enum import Enum
class UserRole(str, Enum):
ADMIN = "admin"
MODERATOR = "moderator"
USER = "user"
class User(BaseModel):
id: int
username: str
email: str
role: UserRole
@app.get("/admin/stats")
async def get_admin_stats(current_user: User = Depends(get_current_user)):
if current_user.role != UserRole.ADMIN:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only admins can access this"
)
return {"users": 1000, "revenue": 50000}
@app.post("/posts/")
async def create_post(post: PostCreate, current_user: User = Depends(get_current_user)):
if current_user.role not in [UserRole.ADMIN, UserRole.MODERATOR]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only admins and moderators can create posts"
)
return {"id": 1, **post.dict()}async def require_admin(current_user: User = Depends(get_current_user)):
if current_user.role != UserRole.ADMIN:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin access required"
)
return current_user
async def require_moderator_or_admin(current_user: User = Depends(get_current_user)):
if current_user.role not in [UserRole.ADMIN, UserRole.MODERATOR]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Moderator or admin access required"
)
return current_user
# Usage
@app.get("/admin/users", dependencies=[Depends(require_admin)])
async def list_all_users():
return db.get_all_users()
@app.delete("/posts/{post_id}", dependencies=[Depends(require_moderator_or_admin)])
async def delete_post(post_id: int, current_user: User = Depends(get_current_user)):
# User already verified as moderator/admin
return db.delete_post(post_id)class Permission(str, Enum):
READ = "read"
CREATE = "create"
UPDATE = "update"
DELETE = "delete"
MANAGE_USERS = "manage_users"
MANAGE_ROLES = "manage_roles"
# Define role permissions
ROLE_PERMISSIONS = {
UserRole.ADMIN: [
Permission.READ,
Permission.CREATE,
Permission.UPDATE,
Permission.DELETE,
Permission.MANAGE_USERS,
Permission.MANAGE_ROLES
],
UserRole.MODERATOR: [
Permission.READ,
Permission.CREATE,
Permission.UPDATE,
Permission.DELETE
],
UserRole.USER: [
Permission.READ,
Permission.CREATE
]
}
def check_permission(required_permission: Permission):
async def permission_checker(current_user: User = Depends(get_current_user)):
user_permissions = ROLE_PERMISSIONS.get(current_user.role, [])
if required_permission not in user_permissions:
logger.warning(f"User {current_user.id} attempted unauthorized action: {required_permission}")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=f"Permission denied: {required_permission}"
)
return current_user
return permission_checker
# Usage
@app.post("/posts/", dependencies=[Depends(check_permission(Permission.CREATE))])
async def create_post(post: PostCreate):
return {"id": 1, **post.dict()}
@app.delete("/posts/{post_id}", dependencies=[Depends(check_permission(Permission.DELETE))])
async def delete_post(post_id: int):
return {"status": "deleted"}
@app.post("/users/ban/{user_id}", dependencies=[Depends(check_permission(Permission.MANAGE_USERS))])
async def ban_user(user_id: int):
db.ban_user(user_id)
logger.info(f"User {user_id} banned")
return {"status": "banned"}RBAC is essential for:
Example - E-commerce platform:
class EcomRole(str, Enum):
ADMIN = "admin"
VENDOR = "vendor"
CUSTOMER = "customer"
@app.post("/products/", dependencies=[Depends(check_permission(Permission.CREATE))])
async def create_product(product: ProductCreate, current_user: User = Depends(get_current_user)):
if current_user.role == EcomRole.VENDOR:
product.vendor_id = current_user.id
elif current_user.role == EcomRole.ADMIN:
# Admin can create products for any vendor
pass
return db.create_product(product)
@app.get("/analytics", dependencies=[Depends(check_permission(Permission.MANAGE_USERS))])
async def get_analytics(current_user: User = Depends(get_current_user)):
if current_user.role == EcomRole.VENDOR:
return db.get_vendor_analytics(current_user.id)
else: # ADMIN
return db.get_global_analytics()Ready to explore more? Check out the advanced section for production patterns and edge cases.
Resources
Ojasa Mirai
Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.
Learn Deep • Build Real • Verify Skills • Launch Forward