Следующим шагом будет защитить доступ к остальным компонентам API, от доступа без сессионного ключа. Для этого воспользуемся классом FastApi security и добавим в требования заголовка запроса тег авторизации.
Получим итоговый роутинг auth.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# -*- coding: utf-8 -*-
"""Different helper-functions to work with users."""
В предыдущей статье был рассмотрен запуск сервера и доступ к нему. Одно НО, доступ этот осуществляется или с локального ПК (в main.py), как вы видели присутствует строчка:
Если host поменять например на 0.0.0.0, сервер «из вне» будет конечно доступен, но по нестандартному порту и не по защищенному протоколу. Однако есть способ «завернуть» весь трафик в https через проксирование в apache/ngnix.
Для apache необходимо установить модуль proxy:
1
2
sudo a2enmod proxy proxy_http
sudo service apache2 restart
И в настройки VirtualHost сайта добавить:
1
2
ProxyPass/http://127.0.0.1:8000
ProxyPassReverse/http://127.0.0.1:8000
Для ngnix к сожалению не могу дать примера, т.к. обычно не использую.
Однако вместо ожидаемой передачи заголовка, curl в упор возвращает ровно ничего:
Гугл помог выяснить, что ключевое слово Authorization зарезервированно для использования в Header. На https://stackoverflow.com было подсказано и направление куда копать. А именно, использовать обертку Security:
Долгое время был любителем по изобретать велосипед, и городил собственные реализации API для внешних систем. Да получалось. Да работало. Но если честно, всегда был в этих API бардак. Документации толковой не было, примеров соответственно тоже. Ну правда работал с этими API собственно практически один я, это и спасало от тухлых помидоров 😉
Решил попробовать таки в следующем своем проекте воспользоваться сторонними решениями для документирования и написания API. Выбор пал на FastApi для python. Собственно дальше просто «рыба» с основными фишками которую можно использовать далее расширяя.
Разберем файл main.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import uvicorn
from fastapi import FastAPI
from app.routers import hash
tags_metadata=[
{"name":"use-hash","description":"Создание хэша по логину, паролю и секрету (если есть)"},
{"name":"delete","description":"Удаление хэга по его *ID*.",},
]
app=FastAPI(title="OCPI API documentation",description="Инструментарий для работы по протоколу OCPI",
Что происходит в этом скрипте? Сначала инициализируется ядро FastApi:
1
2
3
app=FastAPI(title="OCPI API documentation",description="Инструментарий для работы по протоколу OCPI",
version="0.0.2",openapi_tags=tags_metadata,)
Т.е. обявляем название API, описание и присваиваем разделы которые будут отображаться в документации http://127.0.0.1:8000/docs
Далее подключаем роутинг из файла /app/routers/hash.py:
1
app.include_router(hash.router,prefix="/v1")
Этих роутингов естественно может быть не ограниченное количество
Для того чтобы FastApi мог сформировать документацию, необходимо её чуть подготовить. За это отвечают «схемы». Например создадим схему /app/schemas/hash.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf-8 -*-
from typing import Optional
from pydantic import BaseModel,Field
classhash_out(BaseModel):
""" Что Выходит """
hash:str=Field(...,title="Хэш созданый на основе логина пароля",example="iauwhfpseurh e")
Что у нас тут? А вот что: мы объявляем, что 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? Для этого изменим объявление функции, добавив помимо модели, еще и заголовки:
Т.е. нам придется использовать не обычно используемый response_model, для указания класса со схемой ответа, а response, который позволяет указать шаблон при определенном коде ответа. В результате общий файл роута hash.py получается такой:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# -*- coding: utf-8 -*-
"""Different helper-functions to work with users."""
import json
import fastapi
from fastapi import APIRouter,Depends,Request,Header,Response