Короткий ответ
RBAC реализуют через явную модель данных «пользователь → роль → разрешения», где проверка прав на каждом защищённом эндпоинте сверяет набор разрешений текущей роли пользователя с разрешением, требуемым для конкретного действия, а не хардкодит список ролей внутри каждого обработчика.
Как это работает подробнее
В БД хранятся роли (admin, manager, viewer) и связанные с ними разрешения (create_order, delete_user и т.д.), пользователь может иметь одну или несколько ролей; при запросе middleware или декоратор проверяет, есть ли у набора разрешений пользователя нужное разрешение для запрошенной операции.
Пример кода
example.py
from functools import wraps
def require_permission(permission_name):
def decorator(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if permission_name not in request.user.role.permissions:
return Response(status=403)
return view_func(request, *args, **kwargs)
return wrapper
return decorator
@require_permission("delete_order")
def delete_order_view(request, order_id):
delete_order(order_id)
return Response(status=204)Что использовать на практике
- Практика. Разрешения стоит делать достаточно гранулярными для реальных бизнес-сценариев, но не чрезмерно детальными; для сложных случаев, когда доступ зависит ещё и от владения ресурсом, RBAC дополняют проверкой на уровне объекта (object-level permission), а не только роли.
Подводные камни
- Риск. Хардкодят проверки вида
if user.role == "admin"в десятках мест кода, из-за чего добавление новой роли требует правок по всему коду; путают роль с разрешением, выдавая слишком широкую роль там, где нужно одно конкретное действие; забывают проверить права на уровне API при наличии проверки только в UI.