Authorization¶
Overview¶
Authorization is based on RBAC (Role-Based Access Control) with tenant isolation enforced at the database level.
Roles¶
| Role | Description |
|---|---|
| admin | Full system access |
| operator | Manage shipments and operations |
| courier | Field operations (scan, deliver) |
| viewer | Read-only access |
Permission Matrix¶
See User Roles for detailed matrix.
Implementation¶
Decorator-based Authorization¶
from functools import wraps
from fastapi import HTTPException, status
def require_role(*allowed_roles):
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
user = get_current_user()
if user.role not in allowed_roles:
raise HTTPException(status_code=403, detail="Forbidden")
return await func(*args, **kwargs)
return wrapper
return decorator
@app.get("/shipments")
@require_role("admin", "operator")
async def get_shipments():
...
Tenant Isolation (RLS)¶
All tenant-scoped queries are enforced via PostgreSQL Row-Level Security:
CREATE POLICY tenant_isolation ON shipments
USING (tenant_id = current_setting('app.current_tenant')::uuid);
The application sets app.current_tenant on each database connection based on the authenticated user's tenant.
Best Practices¶
- Always check role before sensitive operations
- Use RLS as defense in depth (don't rely solely on application code)
- Audit trail - Log authorization failures for security monitoring
- Principle of least privilege - Only grant minimum permissions needed
Tenant Isolation Rules¶
API endpoints enforce tenant isolation at the application level:
| Entity | Filter By | Endpoints |
|---|---|---|
| Shipment | tenant_id |
list, get, update, delete |
| Bag | user_id |
list, get, update, delete, create |
| Flight | user_id |
list, get, update, delete, create |
# Example: List shipments filtered by tenant
@router.get("/shipments")
async def list_shipments(
current_user=Depends(get_current_active_user),
session: AsyncSession = Depends(get_session),
):
repo = ShipmentRepositoryImpl(session)
# Application-level filtering by tenant_id
shipments = await repo.get_all(tenant_id=current_user.tenant_id)
return shipments
Additionally, RLS policies are enforced at the PostgreSQL level for all tenant-scoped tables as a defense-in-depth measure.
Ver también: Authentication · Tenant Isolation Rules