From bb6ee78a0b85436d1c30cdd90830f35c13b92cd3 Mon Sep 17 00:00:00 2001 From: Yurii Motov Date: Tue, 30 Sep 2025 13:02:28 +0200 Subject: [PATCH] Apply changes from latest PRs: 13917 and 14099 --- .../dependencies/dependencies-with-yield.md | 49 +++---------- docs/ru/docs/tutorial/security/oauth2-jwt.md | 68 +++++++++---------- 2 files changed, 43 insertions(+), 74 deletions(-) diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md index dcb22c728..267faa406 100644 --- a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md @@ -35,7 +35,7 @@ FastAPI поддерживает зависимости, которые выпо {* ../../docs_src/dependencies/tutorial007.py hl[4] *} -Код, следующий за оператором `yield`, выполняется после создания ответа, но до его отправки: +Код, следующий за оператором `yield`, выполняется после ответа: {* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} @@ -95,9 +95,11 @@ FastAPI поддерживает зависимости, которые выпо ## Зависимости с `yield` и `HTTPException` { #dependencies-with-yield-and-httpexception } -Вы видели, что можно использовать зависимости с `yield` и иметь блоки `try`, которые отлавливают исключения. +Вы видели, что можно использовать зависимости с `yield` и иметь блоки `try`, которые пытаются выполнить некоторый код, а затем запускают код выхода в `finally`. -Точно так же можно вызвать `HTTPException` или что-то подобное в коде выхода, после `yield`. +Также вы можете использовать `except`, чтобы поймать вызванное исключение и что-то с ним сделать. + +Например, вы можете вызвать другое исключение, например `HTTPException`. /// tip | Подсказка @@ -109,7 +111,7 @@ FastAPI поддерживает зависимости, которые выпо {* ../../docs_src/dependencies/tutorial008b_an_py39.py hl[18:22,31] *} -Альтернативой для отлавливания исключений (и, возможно, для вызова другого `HTTPException`) может быть создание [Пользовательского обработчика исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. +Если вы хотите перехватывать исключения и формировать на их основе пользовательский ответ, создайте [Пользовательский обработчик исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. ## Зависимости с `yield` и `except` { #dependencies-with-yield-and-except } @@ -178,48 +180,15 @@ participant tasks as Background tasks /// tip | Подсказка -На этой диаграмме показан `HTTPException`, но вы также можете вызвать любое другое исключение, которое ловите в зависимости с `yield` или с [Пользовательским обработчиком исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank}. - -Если вы вызываете какое-либо исключение, оно будет передано зависимостям с `yield`, включая `HTTPException`. В большинстве случаев вы захотите повторно вызвать то же самое исключение или новое из зависимости с `yield`, чтобы убедиться, что оно корректно обработано. +Если вы вызовете какое-либо исключение в коде из *функции-обработчика пути*, оно будет передано зависимостям с `yield`, включая `HTTPException`. В большинстве случаев вы захотите повторно вызвать то же самое исключение или новое из зависимости с `yield`, чтобы убедиться, что оно корректно обработано. /// ## Зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами { #dependencies-with-yield-httpexception-except-and-background-tasks } -/// warning | Внимание - -Скорее всего, вам не нужны эти технические подробности, вы можете пропустить этот раздел и продолжить ниже. - -Эти подробности полезны в основном, если вы использовали версию FastAPI до 0.106.0 и использовали ресурсы из зависимостей с `yield` в фоновых задачах. - -/// - -### Зависимости с `yield` и `except`, технические детали { #dependencies-with-yield-and-except-technical-details } - -До FastAPI 0.110.0, если вы использовали зависимость с `yield`, затем ловили исключение с `except` в этой зависимости и не вызывали исключение снова, исключение автоматически пробрасывалось/перенаправлялось обработчикам исключений или внутреннему обработчику ошибок сервера. - -В версии 0.110.0 это было изменено, чтобы исправить неконтролируемое потребление памяти от перенаправленных исключений без обработчика (внутренние ошибки сервера) и сделать поведение согласованным с поведением обычного Python-кода. - -### Фоновые задачи и зависимости с `yield`, технические детали { #background-tasks-and-dependencies-with-yield-technical-details } - -До FastAPI 0.106.0 вызывать исключения после `yield` было невозможно: код выхода в зависимостях с `yield` выполнялся *после* отправки ответа, поэтому [Обработчики исключений](../handling-errors.md#install-custom-exception-handlers){.internal-link target=_blank} уже отрабатывали. - -Так было задумано главным образом для того, чтобы позволить использовать те же объекты, «отданные» зависимостями, внутри фоновых задач, поскольку код выхода выполнялся после завершения фоновых задач. - -Тем не менее, так как это означало ожидание доставки ответа по сети при одновременном ненужном удержании ресурса в зависимости с `yield` (например, соединения с базой данных), это было изменено в FastAPI 0.106.0. - -/// tip | Подсказка - -Кроме того, фоновая задача обычно представляет собой независимый набор логики, который следует обрабатывать отдельно, со своими собственными ресурсами (например, со своим подключением к базе данных). - -Таким образом, код, скорее всего, получится чище. - -/// - -Если вы полагались на это поведение, теперь вам следует создавать ресурсы для фоновых задач внутри самой фоновой задачи и использовать внутри только данные, которые не зависят от ресурсов зависимостей с `yield`. - -Например, вместо того чтобы использовать ту же сессию базы данных, вы создадите новую сессию базы данных внутри фоновой задачи и получите объекты из базы данных с помощью этой новой сессии. А затем, вместо того чтобы передавать объект из базы данных в качестве параметра функции фоновой задачи, вы передадите идентификатор этого объекта, а затем снова получите объект внутри функции фоновой задачи. +Зависимости с `yield` со временем эволюционировали, чтобы покрыть разные сценарии и исправить некоторые проблемы. +Если вы хотите посмотреть, что менялось в разных версиях FastAPI, вы можете прочитать об этом подробнее в продвинутом руководстве: [Продвинутые зависимости — зависимости с `yield`, `HTTPException`, `except` и фоновыми задачами](../../advanced/advanced-dependencies.md#dependencies-with-yield-httpexception-except-and-background-tasks){.internal-link target=_blank}. ## Контекстные менеджеры { #context-managers } ### Что такое «контекстные менеджеры» { #what-are-context-managers } diff --git a/docs/ru/docs/tutorial/security/oauth2-jwt.md b/docs/ru/docs/tutorial/security/oauth2-jwt.md index 57f973d2c..803491f53 100644 --- a/docs/ru/docs/tutorial/security/oauth2-jwt.md +++ b/docs/ru/docs/tutorial/security/oauth2-jwt.md @@ -1,12 +1,12 @@ -# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами +# OAuth2 с паролем (и хешированием), Bearer с JWT-токенами { #oauth2-with-password-and-hashing-bearer-with-jwt-tokens } -Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены JWT и безопасное хеширование паролей. +Теперь, когда у нас определен процесс обеспечения безопасности, давайте сделаем приложение действительно безопасным, используя токены JWT и безопасное хеширование паролей. Этот код можно реально использовать в своем приложении, сохранять хэши паролей в базе данных и т.д. Мы продолжим разбираться, начиная с того места, на котором остановились в предыдущей главе. -## Про JWT +## Про JWT { #about-jwt } JWT означает "JSON Web Tokens". @@ -26,7 +26,7 @@ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4 Если вы хотите поиграть с JWT-токенами и посмотреть, как они работают, посмотрите https://jwt.io. -## Установка `PyJWT` +## Установка `PyJWT` { #install-pyjwt } Нам необходимо установить `pyjwt` для генерации и проверки JWT-токенов на языке Python. @@ -45,10 +45,10 @@ $ pip install pyjwt /// info | Дополнительная информация Если вы планируете использовать алгоритмы цифровой подписи, такие как RSA или ECDSA, вам следует установить зависимость библиотеки криптографии `pyjwt[crypto]`. -Подробнее об этом можно прочитать в документации по установке PyJWT. +Подробнее об этом можно прочитать в документации по установке PyJWT. /// -## Хеширование паролей +## Хеширование паролей { #password-hashing } "Хеширование" означает преобразование некоторого содержимого (в данном случае пароля) в последовательность байтов (просто строку), которая выглядит как тарабарщина. @@ -56,26 +56,26 @@ $ pip install pyjwt Но преобразовать тарабарщину обратно в пароль невозможно. -### Для чего нужно хеширование паролей +### Для чего нужно хеширование паролей { #why-use-password-hashing } Если ваша база данных будет украдена, то вор не получит пароли пользователей в открытом виде, а только их хэши. Таким образом, вор не сможет использовать этот пароль в другой системе (поскольку многие пользователи везде используют один и тот же пароль, это было бы опасно). -## Установка `passlib` +## Установка `pwdlib` { #install-pwdlib } -PassLib - это отличный пакет Python для работы с хэшами паролей. +pwdlib — это отличный пакет Python для работы с хэшами паролей. Он поддерживает множество безопасных алгоритмов хеширования и утилит для работы с ними. -Рекомендуемый алгоритм - "Bcrypt". +Рекомендуемый алгоритм — "Argon2". -Убедитесь, что вы создали и активировали виртуальное окружение, и затем установите PassLib вместе с Bcrypt: +Убедитесь, что вы создали [виртуальное окружение](../../virtual-environments.md){.internal-link target=_blank}, активируйте его, и затем установите pwdlib вместе с Argon2:
```console -$ pip install "passlib[bcrypt]" +$ pip install "pwdlib[argon2]" ---> 100% ``` @@ -83,40 +83,40 @@ $ pip install "passlib[bcrypt]"
/// tip | Подсказка -С помощью `passlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками. +С помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками. Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных. При этом пользователи смогут одновременно входить в систему как из приложения Django, так и из приложения **FastAPI**. /// -## Хеширование и проверка паролей +## Хеширование и проверка паролей { #hash-and-verify-the-passwords } -Импортируйте необходимые инструменты из `passlib`. +Импортируйте необходимые инструменты из `pwdlib`. -Создайте "контекст" PassLib. Именно он будет использоваться для хэширования и проверки паролей. +Создайте экземпляр PasswordHash с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей. /// tip | Подсказка -Контекст PassLib также имеет функциональность для использования различных алгоритмов хеширования, в том числе и устаревших, только для возможности их проверки и т.д. +pwdlib также поддерживает алгоритм хеширования bcrypt, но не включает устаревшие алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib. -Например, вы можете использовать его для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Bcrypt. +Например, вы можете использовать ее для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Argon2 или Bcrypt. И при этом быть совместимым со всеми этими системами. /// Создайте служебную функцию для хэширования пароля, поступающего от пользователя. -А затем создайте другую - для проверки соответствия полученного пароля и хранимого хэша. +А затем создайте другую — для проверки соответствия полученного пароля и хранимого хэша. -И еще одну - для аутентификации и возврата пользователя. +И еще одну — для аутентификации и возврата пользователя. {* ../../docs_src/security/tutorial004_an_py310.py hl[8,49,56:57,60:61,70:76] *} /// note | Технические детали -Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`. +Если проверить новую (фальшивую) базу данных `fake_users_db`, то можно увидеть, как теперь выглядит хэшированный пароль: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. /// -## Работа с JWT токенами +## Работа с JWT токенами { #handle-jwt-tokens } Импортируйте установленные модули. @@ -140,13 +140,13 @@ $ openssl rand -hex 32 Создайте переменную для срока действия токена. -Определите Pydantic Model, которая будет использоваться для формирования ответа на запрос на получение токена. +Определите Pydantic-модель, которая будет использоваться для формирования ответа на запрос на получение токена. Создайте служебную функцию для генерации нового токена доступа. {* ../../docs_src/security/tutorial004_an_py310.py hl[4,7,13:15,29:31,79:87] *} -## Обновление зависимостей +## Обновление зависимостей { #update-the-dependencies } Обновите `get_current_user` для получения того же токена, что и раньше, но на этот раз с использованием JWT-токенов. @@ -156,7 +156,7 @@ $ openssl rand -hex 32 {* ../../docs_src/security/tutorial004_an_py310.py hl[90:107] *} -## Обновление *операции пути* `/token` +## Обновление *операции пути* `/token` { #update-the-token-path-operation } Создайте `timedelta` со временем истечения срока действия токена. @@ -164,7 +164,7 @@ $ openssl rand -hex 32 {* ../../docs_src/security/tutorial004_an_py310.py hl[118:133] *} -### Технические подробности о JWT ключе `sub` +### Технические подробности о JWT ключе `sub` { #technical-details-about-the-jwt-subject-sub } В спецификации JWT говорится, что существует ключ `sub`, содержащий субъект токена. @@ -186,7 +186,7 @@ JWT может использоваться и для других целей, Важно помнить, что ключ `sub` должен иметь уникальный идентификатор для всего приложения и представлять собой строку. -## Проверка в действии +## Проверка в действии { #check-it } Запустите сервер и перейдите к документации: http://127.0.0.1:8000/docs. @@ -201,7 +201,7 @@ JWT может использоваться и для других целей, Username: `johndoe` Password: `secret` -/// check | Заметка +/// check | Проверка Обратите внимание, что нигде в коде не используется открытый текст пароля "`secret`", мы используем только его хэшированную версию. /// @@ -225,10 +225,10 @@ Password: `secret` /// note | Техническая информация -Обратите внимание на заголовок `Authorization`, значение которого начинается с `Bearer`. +Обратите внимание на HTTP-заголовок `Authorization`, значение которого начинается с `Bearer `. /// -## Продвинутое использование `scopes` +## Продвинутое использование `scopes` { #advanced-usage-with-scopes } В OAuth2 существует понятие "диапазоны" ("`scopes`"). @@ -236,9 +236,9 @@ Password: `secret` Затем вы можете передать этот токен непосредственно пользователю или третьей стороне для взаимодействия с вашим API с определенным набором ограничений. -О том, как их использовать и как они интегрированы в **FastAPI**, читайте далее в **Руководстве пользователя**. +О том, как их использовать и как они интегрированы в **FastAPI**, читайте далее в **Расширенном руководстве пользователя**. -## Резюме +## Резюме { #recap } С учетом того, что вы видели до сих пор, вы можете создать безопасное приложение **FastAPI**, используя такие стандарты, как OAuth2 и JWT. @@ -252,10 +252,10 @@ Password: `secret` Он предоставляет вам полную свободу действий, позволяя выбирать то, что лучше всего подходит для вашего проекта. -Вы можете напрямую использовать многие хорошо поддерживаемые и широко распространенные пакеты, такие как `passlib` и `PyJWT`, поскольку **FastAPI** не требует сложных механизмов для интеграции внешних пакетов. +Вы можете напрямую использовать многие хорошо поддерживаемые и широко распространенные пакеты, такие как `pwdlib` и `PyJWT`, поскольку **FastAPI** не требует сложных механизмов для интеграции внешних пакетов. Напротив, он предоставляет инструменты, позволяющие максимально упростить этот процесс без ущерба для гибкости, надежности и безопасности. При этом вы можете использовать и реализовывать безопасные стандартные протоколы, такие как OAuth2, относительно простым способом. -В **Руководстве пользователя** вы можете узнать больше о том, как использовать "диапазоны" ("`scopes`") OAuth2 для создания более точно настроенной системы разрешений в соответствии с теми же стандартами. OAuth2 с диапазонами - это механизм, используемый многими крупными провайдерами сервиса аутентификации, такими как Facebook, Google, GitHub, Microsoft, X (Twitter) и др., для авторизации сторонних приложений на взаимодействие с их API от имени их пользователей. +В **Расширенном руководстве пользователя** вы можете узнать больше о том, как использовать "диапазоны" ("`scopes`") OAuth2 для создания более точно настроенной системы разрешений в соответствии с теми же стандартами. OAuth2 с диапазонами — это механизм, используемый многими крупными провайдерами сервиса аутентификации, такими как Facebook, Google, GitHub, Microsoft, X (Twitter) и др., для авторизации сторонних приложений на взаимодействие с их API от имени их пользователей.