REST API на Django/DRF с собственной JWT-аутентификацией, middleware-обработкой токенов и ролевой моделью доступа (RBAC). Написан без django.contrib.auth — чтобы показать понимание того, как аутентификация и авторизация работают изнутри.
Встроенный auth Django решает большинство задач, и в production я бы его использовал. Здесь — намеренный выбор: разобрать механику до уровня "как это устроено": кастомная модель пользователя, bcrypt-хеширование паролей вручную, JWT без AbstractUser, middleware вместо DRF-аутентификаторов. В разделе Что изменил бы в production объясняю, где такой подход не стал бы применять.
- Python 3.13 / Django 6.0 / DRF 3.16
- PyJWT — генерация и валидация токенов
- bcrypt — хеширование паролей
- SQLite (переключается через
DATABASE_URL)
Доступ строится на четырёх сущностях:
| Сущность | Роль |
|---|---|
CustomUser |
Пользователь с bcrypt-хешем пароля и ссылкой на роль |
Role |
Справочник ролей (Admin, User, ...) |
BusinessElement |
Ресурс/модуль системы (mock_objects, access_rules) |
AccessRule |
CRUD-флаги (can_read/create/update/delete) для пары (Role, BusinessElement) |
Поток запроса:
Request
→ CustomAuthMiddleware # читает Authorization: Bearer <token>,
# декодирует JWT, кладёт user в request.custom_user
→ View
→ @check_access(element_key, action) # проверяет AccessRule перед логикой
Role ──────────┐
├── AccessRule (can_read, can_create, can_update, can_delete)
BusinessElement┘
CustomUser ──── Role
├── core/ # JWT (auth.py), middleware, декоратор @check_access
├── users/ # Регистрация, логин, профиль
├── access/ # Модели ролей/ресурсов/правил, API просмотра правил
├── mock/ # Пример защищённых бизнес-ресурсов
├── config/ # settings.py, urls.py
└── init_db.py # Заполнение БД начальными данными
git clone https://github.com/Lu7474/custom-auth-rbac-api.git
cd custom-auth-rbac-api
pip install -r requirements.txt
python manage.py makemigrations users access mock
python manage.py migrate
python init_db.py
python manage.py runserverdocker-compose up --buildСервер будет доступен на http://localhost:8000.
| Метод | URL | Описание |
|---|---|---|
| POST | /api/users/register/ |
Регистрация |
| POST | /api/users/login/ |
Получить JWT-токен |
| GET | /api/users/profile/ |
Профиль текущего пользователя |
| PATCH | /api/users/profile/ |
Обновить профиль |
| DELETE | /api/users/profile/ |
Soft-delete аккаунта |
| Метод | URL | Требуемое право |
|---|---|---|
| GET | /api/mock/ |
mock_objects:read |
| POST | /api/mock/ |
mock_objects:create |
| GET | /api/access/rules/ |
access_rules:read |
| Роль | Ресурс | Read | Create | Update | Delete |
|---|---|---|---|---|---|
| Admin | mock_objects | ✅ | ✅ | ✅ | ✅ |
| Admin | access_rules | ✅ | ❌ | ✅ | ❌ |
| User | mock_objects | ✅ | ❌ | ❌ | ❌ |
Тестовый администратор: admin@example.com / admin123
Логин:
curl -s -X POST http://localhost:8000/api/users/login/ \
-H "Content-Type: application/json" \
-d '{"email":"admin@example.com","password":"admin123"}'
# → {"token": "eyJ..."}Запрос к защищённому ресурсу:
TOKEN="<token из логина>"
curl -s http://localhost:8000/api/mock/ \
-H "Authorization: Bearer $TOKEN"Создание объекта (требует роль Admin):
curl -s -X POST http://localhost:8000/api/mock/ \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Регистрация:
curl -s -X POST http://localhost:8000/api/users/register/ \
-H "Content-Type: application/json" \
-d '{"email":"user@example.com","password":"pass123","password_confirm":"pass123","first_name":"Ivan","last_name":"Petrov"}'python manage.py testПокрывают:
- регистрацию (успех, несовпадение паролей, дубль email)
- логин (успех, неверный пароль, несуществующий пользователь, inactive-аккаунт)
- невалидный и просроченный JWT
- профиль без токена и с токеном
- матрицу прав: Admin vs User на
mock_objectsиaccess_rules
- Auth-слой — не писал бы свой полностью.
django.contrib.auth+djangorestframework-simplejwtнадёжнее и поддерживаются сообществом. Кастомный auth оправдан только при жёстких ограничениях на зависимости. - RBAC — оставил бы кастомным: встроенные пермишены Django не дают нужной гранулярности по бизнес-ресурсам.
- JWT-секрет — обязательно в переменную окружения, не хардкод в коде.
- SQLite → PostgreSQL для любой prod-нагрузки.
- Тесты — добавил бы property-based тесты для матрицы прав и интеграционные тесты с реальной БД.
Учебно-архитектурный проект. Цель — разобраться с механикой auth/authz на уровне реализации, а не заменить готовые решения.