# Безопасность — первые шаги { #security-first-steps }

Представим, что у вас есть **бэкенд** API на некотором домене.

И у вас есть **фронтенд** на другом домене или на другом пути того же домена (или в мобильном приложении).

И вы хотите, чтобы фронтенд мог аутентифицироваться на бэкенде, используя **имя пользователя** и **пароль**.

Мы можем использовать **OAuth2**, чтобы построить это с **FastAPI**.

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

Воспользуемся инструментами, предоставленными **FastAPI**, чтобы работать с безопасностью.

## Как это выглядит { #how-it-looks }

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

## Создание `main.py` { #create-main-py }

Скопируйте пример в файл `main.py`:

{* ../../docs_src/security/tutorial001_an_py39.py *}

## Запуск { #run-it }

/// info | Дополнительная информация

Пакет <a href="https://github.com/Kludex/python-multipart" class="external-link" target="_blank">`python-multipart`</a> автоматически устанавливается вместе с **FastAPI**, если вы запускаете команду `pip install "fastapi[standard]"`.

Однако, если вы используете команду `pip install fastapi`, пакет `python-multipart` по умолчанию не включается.

Чтобы установить его вручную, убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md){.internal-link target=_blank}, активировали его и затем установили пакет:

```console
$ pip install python-multipart
```

Это связано с тем, что **OAuth2** использует «данные формы» для отправки `username` и `password`.

///

Запустите пример командой:

<div class="termy">

```console
$ fastapi dev main.py

<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
```

</div>

## Проверка { #check-it }

Перейдите к интерактивной документации по адресу: <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.

Вы увидите примерно следующее:

<img src="/img/tutorial/security/image01.png">

/// check | Кнопка авторизации!

У вас уже появилась новая кнопка «Authorize».

А у вашей *операции пути* в правом верхнем углу есть маленький замочек, на который можно нажать.

///

Если нажать на нее, появится небольшая форма авторизации, в которую нужно ввести `username` и `password` (и другие необязательные поля):

<img src="/img/tutorial/security/image02.png">

/// note | Примечание

Неважно, что вы введете в форму — пока это не будет работать. Но мы скоро до этого дойдем.

///

Конечно, это не фронтенд для конечных пользователей, но это отличный автоматический инструмент для интерактивного документирования всего вашего API.

Им может пользоваться команда фронтенда (которой можете быть и вы сами).

Им могут пользоваться сторонние приложения и системы.

И им также можете пользоваться вы сами, чтобы отлаживать, проверять и тестировать то же самое приложение.

## «`password` flow» (аутентификация по паролю) { #the-password-flow }

Теперь давайте немного вернемся и разберемся, что это все такое.

«`password` flow» — это один из способов («flows»), определенных в OAuth2, для обеспечения безопасности и аутентификации.

OAuth2 был спроектирован так, чтобы бэкенд или API были независимы от сервера, который аутентифицирует пользователя.

Но в нашем случае одно и то же приложение **FastAPI** будет работать и с API, и с аутентификацией.

Итак, рассмотрим это с упрощенной точки зрения:

* Пользователь вводит на фронтенде `username` и `password` и нажимает `Enter`.
* Фронтенд (работающий в браузере пользователя) отправляет эти `username` и `password` на конкретный URL в нашем API (объявленный с `tokenUrl="token"`).
* API проверяет этот `username` и `password` и отвечает «токеном» (мы еще ничего из этого не реализовали).
    * «Токен» — это просто строка с некоторым содержимым, которое мы сможем позже использовать для проверки этого пользователя.
    * Обычно у токена установлен срок действия: он истекает через некоторое время.
        * Поэтому пользователю придется снова войти в систему в какой‑то момент.
        * И если токен украдут, риск меньше: это не постоянный ключ, который будет работать вечно (в большинстве случаев).
* Фронтенд временно где‑то хранит этот токен.
* Пользователь кликает во фронтенде, чтобы перейти в другой раздел веб‑приложения.
* Фронтенду нужно получить дополнительные данные из API.
    * Но для этого для конкретной конечной точки нужна аутентификация.
    * Поэтому, чтобы аутентифицироваться в нашем API, он отправляет HTTP-заголовок `Authorization` со значением `Bearer ` плюс сам токен.
    * Если токен содержит `foobar`, то содержимое заголовка `Authorization` будет: `Bearer foobar`.

## Класс `OAuth2PasswordBearer` в **FastAPI** { #fastapis-oauth2passwordbearer }

**FastAPI** предоставляет несколько средств на разных уровнях абстракции для реализации этих функций безопасности.

В этом примере мы будем использовать **OAuth2**, с потоком **Password**, используя токен **Bearer**. Для этого мы используем класс `OAuth2PasswordBearer`.

/// info | Дополнительная информация

Токен «bearer» — не единственный вариант.

Но для нашего случая он — лучший.

И он может быть лучшим для большинства случаев использования, если только вы не являетесь экспертом по OAuth2 и точно знаете, почему другой вариант лучше подходит под ваши нужды.

В этом случае **FastAPI** также предоставляет инструменты, чтобы его реализовать.

///

При создании экземпляра класса `OAuth2PasswordBearer` мы передаем параметр `tokenUrl`. Этот параметр содержит URL, который клиент (фронтенд, работающий в браузере пользователя) будет использовать для отправки `username` и `password`, чтобы получить токен.

{* ../../docs_src/security/tutorial001_an_py39.py hl[8] *}

/// tip | Подсказка

Здесь `tokenUrl="token"` ссылается на относительный URL `token`, который мы еще не создали. Поскольку это относительный URL, он эквивалентен `./token`.

Поскольку мы используем относительный URL, если ваш API расположен по адресу `https://example.com/`, то он будет ссылаться на `https://example.com/token`. А если ваш API расположен по адресу `https://example.com/api/v1/`, то он будет ссылаться на `https://example.com/api/v1/token`.

Использование относительного URL важно для того, чтобы ваше приложение продолжало работать даже в таком продвинутом случае, как [За прокси-сервером](../../advanced/behind-a-proxy.md){.internal-link target=_blank}.

///

Этот параметр не создает конечную точку / *операцию пути*, а объявляет, что URL `/token` — это тот, который клиент должен использовать для получения токена. Эта информация используется в OpenAPI, а затем в интерактивных системах документации по API.

Скоро мы также создадим и саму операцию пути.

/// info | Дополнительная информация

Если вы очень строгий «питонист», вам может не понравиться стиль имени параметра `tokenUrl` вместо `token_url`.

Это потому, что используется то же имя, что и в спецификации OpenAPI. Так, если вам нужно разобраться подробнее в какой‑то из этих схем безопасности, вы можете просто скопировать и вставить это имя, чтобы найти больше информации.

///

Переменная `oauth2_scheme` — это экземпляр `OAuth2PasswordBearer`, но она также «вызываемая».

Ее можно вызвать так:

```Python
oauth2_scheme(some, parameters)
```

Поэтому ее можно использовать вместе с `Depends`.

### Использование { #use-it }

Теперь вы можете передать `oauth2_scheme` как зависимость с `Depends`.

{* ../../docs_src/security/tutorial001_an_py39.py hl[12] *}

Эта зависимость предоставит `str`, который будет присвоен параметру `token` *функции-обработчика пути*.

**FastAPI** будет знать, что может использовать эту зависимость для определения «схемы безопасности» в схеме OpenAPI (и в автоматической документации по API).

/// info | Технические детали

**FastAPI** будет знать, что может использовать класс `OAuth2PasswordBearer` (объявленный в зависимости) для определения схемы безопасности в OpenAPI, потому что он наследуется от `fastapi.security.oauth2.OAuth2`, который, в свою очередь, наследуется от `fastapi.security.base.SecurityBase`.

Все утилиты безопасности, интегрируемые с OpenAPI (и автоматической документацией по API), наследуются от `SecurityBase`, — так **FastAPI** понимает, как интегрировать их в OpenAPI.

///

## Что он делает { #what-it-does }

Он будет искать в запросе заголовок `Authorization`, проверять, что его значение — это `Bearer ` плюс некоторый токен, и вернет токен как `str`.

Если заголовок `Authorization` отсутствует или его значение не содержит токен `Bearer `, он сразу ответит ошибкой со статус-кодом 401 (`UNAUTHORIZED`).

Вам даже не нужно проверять наличие токена, чтобы вернуть ошибку. Вы можете быть уверены: если ваша функция была выполнена, в этом токене будет `str`.

Это уже можно попробовать в интерактивной документации:

<img src="/img/tutorial/security/image03.png">

Мы пока не проверяем валидность токена, но для начала это уже неплохо.

## Резюме { #recap }

Таким образом, всего за 3–4 дополнительные строки у вас уже есть некая примитивная форма защиты.
