FastApi: авторизированный вход

Из предыдущей статьи у нас есть некий вызов API после выполнения которого у нас на руках будет некий сессионый ключ.

Попробуем теперь используя этот сессионый ключ, запросить некую информацию о пользователе. Для этого добавим в схему auth.py классы:

Следующим шагом будет защитить доступ к остальным компонентам API, от доступа без сессионного ключа. Для этого воспользуемся классом FastApi security и добавим в требования заголовка запроса тег авторизации.

Получим итоговый роутинг auth.py:

В результате мы можем увидеть в документации появившийся «замочек»:

При попытке выполнения запроса без авторизации, соответственно получим ошибку аторизации:

Настройка внешнего доступа к API

В предыдущей статье был рассмотрен запуск сервера и доступ к нему. Одно НО, доступ этот осуществляется или с локального ПК (в main.py), как вы видели присутствует строчка:

Если host поменять например на 0.0.0.0, сервер «из вне» будет конечно доступен, но по нестандартному порту и не по защищенному протоколу. Однако есть способ «завернуть» весь трафик в https через проксирование в apache/ngnix.

Для apache необходимо установить модуль proxy:

И в настройки VirtualHost сайта добавить:

Для ngnix к сожалению не могу дать примера, т.к. обычно не использую.

FastApi: передача заголовка Authorization в header

Не тривиальная задача, которая потребовала двух дней поиска решения.

Казалось бы, всё решается просто:

Однако вместо ожидаемой передачи заголовка, curl в упор возвращает ровно ничего:

Гугл помог выяснить, что ключевое слово Authorization зарезервированно для использования в Header. На https://stackoverflow.com было подсказано и направление куда копать. А именно, использовать обертку Security:

Пишем API правильно. На примере FastApi

Долгое время был любителем по изобретать велосипед, и городил собственные реализации API для внешних систем. Да получалось. Да работало. Но если честно, всегда был в этих API бардак. Документации толковой не было, примеров соответственно тоже. Ну правда работал с этими API собственно практически один я, это и спасало от тухлых помидоров 😉

Решил попробовать таки в следующем своем проекте воспользоваться сторонними решениями для документирования и написания API. Выбор пал на FastApi для python. Собственно дальше просто «рыба» с основными фишками которую можно использовать далее расширяя.

Разберем файл main.py:

Что происходит в этом скрипте? Сначала инициализируется ядро FastApi:

Т.е. обявляем название API, описание и присваиваем разделы которые будут отображаться в документации http://127.0.0.1:8000/docs

Далее подключаем роутинг из файла /app/routers/hash.py:

Этих роутингов естественно может быть не ограниченное количество

Для того чтобы FastApi мог сформировать документацию, необходимо её чуть подготовить. За это отвечают «схемы». Например создадим схему /app/schemas/hash.py:

Т.е. создаем классы с переменными которые могут быть входящими или исходящими пакетами работы API.

Далее создаем непосредственно файл работы с роутом hash:

Что у нас тут? А вот что: мы объявляем, что FastAPI должен перенаправлять весь вход по методу POST с URL /hash (на самом деле /v1/hash, т.к. роутин объявили с префиксом v1) в функцию async def hash. В качестве исходящих значений, в response_model указываем схему hash_out заданную в схемах выше. Так -же установим тэг tags=[«use-hash»], для того чтоб функция API была красиво подписана. В качестве входящих параметров функции hash, указываем соответственно модель с классом hash_in

Если хочется «перехватывать» не только POST запросы, но и GET, то вызов чуть изменится:

Т.е. мы изменили вызов на get и в функцию добавили Depends(), т.к. входящие параметры попадают не в виде в данном случае JSON, а в качестве параметров вида: /v1/hash?login=aaa&passowd=bbb, т.е. их нужно конвертировать предварительно в JSON

А что делать, если помимо входящих параметров из POST запроса (ну или GET/PUT/DELETE и т.д), необходимо еще и обработать пришедшие заголовки Headers? Для этого изменим объявление функции, добавив помимо модели, еще и заголовки:

Тогда если в запросе будет присутствовать заголовок Secret-Code-In, то он будет передан в переменную secret

А если нам необходимо не только обработать входящие заголовки, но отдать их при ответе? Тут тогда получиться несколько сложнее.

Т.е. нам придется использовать не обычно используемый response_model, для указания класса со схемой ответа, а response, который позволяет указать шаблон при определенном коде ответа. В результате общий файл роута hash.py получается такой:

Что в принципе покрывает используемые в большинстве случаев кейсы использования