Это приложение - это mockup - сервис аутентификации, разработанный с использованием FastAPI. В нем представлен базовый вариант аутентификации с помощью JWT - токенов и возможностью подключить двухфакторную авторизацию (или TFA - Two Factor Authentication).
Двухфакторная авторизация
Двухфакторную авторизацию можно включить двумя следующими способами:
- Email (OTP - токен будет отправлен по почте)
- Генератор кодов (при активации будет доступен QR - код, который можно просканировать и загрузить многоразовый OTP - токен в любое приложение для авторизации, например Google Authenticator)
В представленном сервисе доступна только TOTP - версия OTP - протокола валидации, которая базируется на timestamp'е и персональном ключе каждого пользователя.
Backup токены
При активации TFA, вне зависимости от выбранного типа авторизации, на почту будет направлено письмо с 5 backup - токенами, которыми можно воспользоваться в случае если QR - код был утерян или если по какой-то причине невозможно получить токен. Данные токены - одноразовые, если все токены израсходованы - восстановить QR - код для того же пользователя без сброса невозможно.
Email - сервис
Отправка писем осуществляется с помощью yagmail, настроенного на почту с помощью app password внутри Gmail. Задачи на отправку писем отправляются в брокер RabbitMQ, где уже перенаправляются в Celery для обработки.
Сервисы
Все сервисы разворачиваются с помощью Docker, непосредственно развертывание происходит с помощью docker-compose. Для хранения данных пользователя используется PostgreSQL, в качестве брокера очереди - RabbitMQ, Celery используется для обработки и распределения задач, а Redis используется как persistent бэкенд, хранящий результаты задач. При развертывании сервиса так же доступен сервис Flower для мониторинга задач в Celery и интерактивная документация для FastAPI, в которой можно проверить часть функционала. Порты, адреса и другие параметры для данных сервисов задаются в .env-файле, дефолтные значения для каждого сервиса можно увидеть в таблице ниже:
| Сервис | Название контейнера | Порт |
|---|---|---|
| FastAPI | fastapi_auth | 8001 |
| PostgresDB | fastapi_auth-db | 5454 |
| Redis | fastapi_auth-cache | 6389 |
| RabbitMQ | fastapi_auth-rabbitmq | 15672 |
| Celery worker | fastapi_auth-celery | |
| Flower | fastapi_auth-flower | 5557 |
Модель User имеет One to One связь с моделью Device. Device имеет One to Many связь с моделью BackupTokens.
full_name- имя пользователяemail- логин пользвателя; так же используется для отправки письмаhashed_password- пароль пользователя; после успешной регистрации хешируетсяtfa_enabled- true / false поле для обозначения флага доступности TFA для этого пользователя
user_id- ID пользователяkey- здесь хранится зашифрованная версия OTP - ключа пользователяdevice_type- это поле определяет тип устройства, которое будет использоваться при авторизации:emailилиcode_generator
device_id- ID устройстваtoken- случайно генерируемый TOTP - token
Эндпоинты можно частично протестировать через FastAPI Swagger. Он будет доступен по адресу /docs на том компьютере,
где вы развернули сервис (по умолчанию localhost:8001/docs). Ниже будут указаны curl - команды, которыми можно установить,
получить и сменить как JWT - токены, так и QR - код.
-
/api/v1/auth/signupPOST - Создает нового пользователя.
Ключ
deviceтребуется только еслиtfa_enabled=true;device_typeдолжен быть либоemail, либоcode_generatorПример тела запроса
{ "email": "user@example.com", "tfa_enabled": true, "full_name": "string", "password": "123456", "device": { "device_type": "email" } }Пример curl - запроса (
--outputсохранит изображение, только если тип устройства был указан какcode_generator)curl -X "POST" \ "http://localhost:8001/api/v1/auth/signup" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ -d "{ "email": "user@example.com", "tfa_enabled": true, "full_name": "string", "password": "123456", "device": { "device_type": "email" } }" --output my_qrcode.jpg
-
/api/v1/auth/loginPOST - Аутентификация нового пользователя
Тело запроса
EMAIL PASSWORDcurl
curl -X "POST" \ "http://localhost:8001/api/v1/auth/login" \ -H "accept: application/json" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=&username={{ EMAIL }}&password={{ PASSWORD }}&scope=&client_id=&client_secret="
Тело ответа
ACCESS_JWT_TOKEN REFRESH_JWT_TOKEN -
/api/v1/auth/test-tokenGET - Проверить, авторизован ли пользователь, с помощью полученного на предыдущем шагу JWT - токена.
Тело запроса
ACCESS_JWT_TOKENПример curl - запроса
curl -X "GET" \ "http://localhost:8001/api/v1/auth/test-token" \ -H "accept: application/json" \ -H "Authorization: Bearer {{ ACCESS_JWT_TOKEN }}"
-
/api/v1/auth/refreshPOST - при предоставлении
REFRESH_JWT_TOKENвозвращает новыйACCESS_JWT_TOKENТело запроса
{ "refresh_token": "{{ REFRESH_JWT_TOKEN }}" }Пример curl - запроса
curl -X "POST" \ "http://localhost:8001/api/v1/auth/refresh" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ -d "{ "refresh_token": "{{ MY_JWT_REFRESH_TOKEN }}" }"
-
/api/v1/tfa/login_tfa?tfa_token=POST - Это второй шаг после авторизации для пользователей со включенной TFA. Для этого шага необходимо иметь TOTP - токен и временный JWT - токен, полученный после прохождения этапа
AuthorizationПример curl - запроса
curl -X "POST" \ "http://localhost:8001/api/v1/tfa/login_tfa?tfa_token={{ MY_TOTP_TOKEN }}" \ -H "accept: application/json" \ -H "Authorization: Bearer {{ PRE_TFA_JWT_ACCESS_TOKEN }}" \ -d ""
-
/api/v1/tfa/recover_tfa?tfa_backup_token=POST - Этот шаг необходим для пользователей с включенным TFA, которые не получили TOTP-токен, но получили backup-токены. На этом шагу они могут использовать эти токены для воостановления доступа. Для этого шага необходимо иметь временный JWT - токен, полученный после прохождения этапа
Authorization.Пример curl - запроса
curl -X "POST" \ "http://localhost:5555/api/v1/tfa/recover_tfa?tfa_backup_token={{ MY_BACKUP_TOTP_TOKEN }}" \ -H "accept: application/json" \ -H "Authorization: Bearer {{ MY_PRE_TFA_JWT_ACCESS_TOKEN }}" \ -d ""
-
/api/v1/tfa/get_my_qrcodeGET - Эндпоинт для повторного получения QR - кода (только для пользователей с типом устройства
code_generator)Пример curl - запроса
curl -X "GET" \ "http://localhost:5555/api/v1/tfa/get_my_qrcode" \ -H "accept: application/json" \ -H "Authorization: Bearer {{ MY_JWT_ACCESS_TOKEN }}" --output my_recovered_qr_code.png
-
/api/v1/tfa/enable_tfaPUT - Включение TFA для пользователей, которые не выбрали этот режим при регистрации.
device_typeдолжен быть либоemail, либоcode_generatorТело запроса
{ "device_type": "code_generator" }Пример curl - запроса (
--outputсохранит изображение, только если тип устройства был указан как `code_generator)curl -X "PUT" \ "http://localhost:8001/api/v1/tfa/enable_tfa" \ -H "accept: application/json" \ -H "Authorization: Bearer {{ MY_JWT_ACCESS_TOKEN }}" \ -H "Content-Type: application/json" \ -d "{ "device_type": "code_generator" }" --output my_new_qr_code.jpg
-
/api/v1/users/usersGET - Эндпоинт, не требующий авторизации и возвращающий список всех пользователей в базе данных.
curl
curl -X "GET" \ "http://localhost:8001/api/v1/users/users" \ -H "accept: application/json"
-
/api/v1/tasks/test-celeryGET - Эндпоинт для проверки функции отправки почты.
Тело запроса (%40 в запросе равноценно @)
email_address%40mail.serviceПример curl - запроса
curl -X "GET" \ "http://localhost:8001/api/v1/tasks/test-celery?email_addr=email_address%40mail.service" \ -H "accept: application/json"
-
/api/v1/tasks/taskstatus?task_id=GET - Эндпоинт для получения статуса задачи.
?task_idвовращается эндпоинтом ``/api/v1/tasks/test-celery`.curl
curl -X "GET" \ "http://localhost:8001/api/v1/tasks/taskstatus?task_id={{ TASK_ID }}" \ -H "accept: application/json"
Модули в этой части сервиса отвечают за взаимодействие с базой данных.
Модули в этой части сервиса отвечают за общую логику работы программы.
Чтобы запустить все сервисы, из корневой папки сервиса необходимо написать:
docker-compose -f deploy/docker-compose.yaml up -ddocker-compose автоматически соберет все необходимые образы и запустит все сервисы самостоятельно на указанных портах.
FastAPI - сервер по умолчанию запускается на порту 8001, интерактивная документация FastAPI доступна по адресу
http://localhost:8001/docs#/
Чтобы получить логи основного контейнера, в терминале можно написать:
dockerfiles logs --tail 200 -f fastapi_auth- Не все эндпоинты можно проверить через Swagger - это ограничение FastAPI, через curl все запросы отрабатывают
- TOTP - токены продолжают отправляться при выборе устройства email - это необходимо для возможности восстановить доступ
- Отсутствуют тесты
- Отсутствует логирование