From b7ccf4dcb486d5174c8d616622a39e60cbccce13 Mon Sep 17 00:00:00 2001 From: Neizvestnyj Date: Wed, 23 Jul 2025 16:46:56 +0300 Subject: [PATCH 1/4] added `pwdlib` support with argon2, instead of `passlib` --- docs/en/docs/tutorial/security/oauth2-jwt.md | 20 ++++++++++---------- docs/ru/docs/tutorial/security/oauth2-jwt.md | 20 ++++++++++---------- docs_src/security/tutorial004_an_py310.py | 8 ++++---- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index 8644db45c..a09af7c1f 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -64,20 +64,20 @@ If your database is stolen, the thief won't have your users' plaintext passwords So, the thief won't be able to try to use that password in another system (as many users use the same password everywhere, this would be dangerous). -## Install `passlib` +## Install `pwdlib` -PassLib is a great Python package to handle password hashes. +pwdlib is a great Python package to handle password hashes. It supports many secure hashing algorithms and utilities to work with them. -The recommended algorithm is "Bcrypt". +The recommended algorithm is "Argon2". -Make sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install PassLib with Bcrypt: +Make sure you create a [virtual environment](../../virtual-environments.md){.internal-link target=_blank}, activate it, and then install pwdlib with Argon2:
```console -$ pip install "passlib[bcrypt]" +$ pip install "pwdlib[argon2]" ---> 100% ``` @@ -86,7 +86,7 @@ $ pip install "passlib[bcrypt]" /// tip -With `passlib`, you could even configure it to be able to read passwords created by **Django**, a **Flask** security plug-in or many others. +With `pwdlib`, you could even configure it to be able to read passwords created by **Django**, a **Flask** security plug-in or many others. So, you would be able to, for example, share the same data from a Django application in a database with a FastAPI application. Or gradually migrate a Django application using the same database. @@ -96,15 +96,15 @@ And your users would be able to login from your Django app or from your **FastAP ## Hash and verify the passwords -Import the tools we need from `passlib`. +Import the tools we need from `pwdlib`. -Create a PassLib "context". This is what will be used to hash and verify passwords. +Create a PasswordHash instance with recommended settings — it will be used for hashing and verifying passwords. /// tip -The PassLib context also has functionality to use different hashing algorithms, including deprecated old ones only to allow verifying them, etc. +pwdlib also supports the bcrypt hashing algorithm but does not include legacy algorithms — for working with outdated hashes, it is recommended to use the passlib library. -For example, you could use it to read and verify passwords generated by another system (like Django) but hash any new passwords with a different algorithm like Bcrypt. +For example, you could use it to read and verify passwords generated by another system (like Django) but hash any new passwords with a different algorithm like Argon2 or Bcrypt. And be compatible with all of them at the same time. diff --git a/docs/ru/docs/tutorial/security/oauth2-jwt.md b/docs/ru/docs/tutorial/security/oauth2-jwt.md index 1195fad21..68789a3ec 100644 --- a/docs/ru/docs/tutorial/security/oauth2-jwt.md +++ b/docs/ru/docs/tutorial/security/oauth2-jwt.md @@ -62,20 +62,20 @@ $ pip install pyjwt Таким образом, вор не сможет использовать этот пароль в другой системе (поскольку многие пользователи везде используют один и тот же пароль, это было бы опасно). -## Установка `passlib` +## Установка `pwdlib` -PassLib - это отличный пакет Python для работы с хэшами паролей. +pwdlib - это отличный пакет Python для работы с хэшами паролей, пришедший на замену passlib. Он поддерживает множество безопасных алгоритмов хеширования и утилит для работы с ними. -Рекомендуемый алгоритм - "Bcrypt". +Рекомендуемый алгоритм - "Argon2". -Убедитесь, что вы создали и активировали виртуальное окружение, и затем установите PassLib вместе с Bcrypt: +Убедитесь, что вы создали и активировали виртуальное окружение, и затем установите pwdlib вместе с Argon2:
```console -$ pip install "passlib[bcrypt]" +$ pip install "pwdlib[argon2]" ---> 100% ``` @@ -83,7 +83,7 @@ $ pip install "passlib[bcrypt]"
/// tip | Подсказка -С помощью `passlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками. +С помощью `pwdlib` можно даже настроить его на чтение паролей, созданных **Django**, плагином безопасности **Flask** или многими другими библиотеками. Таким образом, вы сможете, например, совместно использовать одни и те же данные из приложения Django в базе данных с приложением FastAPI. Или постепенно мигрировать Django-приложение, используя ту же базу данных. @@ -92,14 +92,14 @@ $ pip install "passlib[bcrypt]" ## Хеширование и проверка паролей -Импортируйте необходимые инструменты из `passlib`. +Импортируйте необходимые инструменты из `pwdlib`. -Создайте "контекст" PassLib. Именно он будет использоваться для хэширования и проверки паролей. +Создайте экземпляр `PasswordHash` с рекомендованными настройками — он будет использоваться для хэширования и проверки паролей. /// tip | Подсказка -Контекст PassLib также имеет функциональность для использования различных алгоритмов хеширования, в том числе и устаревших, только для возможности их проверки и т.д. +pwdlib также имеет функциональность для использования алгоритма хэширования bcrypt, но не поддерживает старые алгоритмы — для работы с устаревшими хэшами рекомендуется использовать библиотеку passlib. -Например, вы можете использовать его для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Bcrypt. +Например, вы можете использовать его для чтения и проверки паролей, сгенерированных другой системой (например, Django), но хэшировать все новые пароли другим алгоритмом, например Argon2 или Bcrypt. И при этом быть совместимым со всеми этими системами. /// diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py index a3f74fc0e..807f28990 100644 --- a/docs_src/security/tutorial004_an_py310.py +++ b/docs_src/security/tutorial004_an_py310.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -46,7 +46,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -54,11 +54,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): From 071d9043883b62f423c480d26f8ae82ae7b6644f Mon Sep 17 00:00:00 2001 From: Neizvestnyj Date: Fri, 25 Jul 2025 15:17:25 +0300 Subject: [PATCH 2/4] replace `passlib` to `pwdlib` --- docs_src/security/tutorial004.py | 8 ++++---- docs_src/security/tutorial004_an.py | 8 ++++---- docs_src/security/tutorial004_an_py39.py | 8 ++++---- docs_src/security/tutorial004_py310.py | 8 ++++---- docs_src/security/tutorial005.py | 8 ++++---- docs_src/security/tutorial005_an.py | 8 ++++---- docs_src/security/tutorial005_an_py310.py | 8 ++++---- docs_src/security/tutorial005_an_py39.py | 8 ++++---- docs_src/security/tutorial005_py310.py | 8 ++++---- docs_src/security/tutorial005_py39.py | 8 ++++---- 10 files changed, 40 insertions(+), 40 deletions(-) diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py index 222589618..ec7c818bf 100644 --- a/docs_src/security/tutorial004.py +++ b/docs_src/security/tutorial004.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -46,7 +46,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -54,11 +54,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py index e2221cd39..31c97a0d1 100644 --- a/docs_src/security/tutorial004_an.py +++ b/docs_src/security/tutorial004_an.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel from typing_extensions import Annotated @@ -47,7 +47,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -55,11 +55,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py index b33d677ed..d2a254ba0 100644 --- a/docs_src/security/tutorial004_an_py39.py +++ b/docs_src/security/tutorial004_an_py39.py @@ -5,7 +5,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -46,7 +46,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -54,11 +54,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py index d46ce26bf..b7d5b958b 100644 --- a/docs_src/security/tutorial004_py310.py +++ b/docs_src/security/tutorial004_py310.py @@ -4,7 +4,7 @@ import jwt from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel # to get a string like this run: @@ -45,7 +45,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -53,11 +53,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py index ccad07969..710d792cc 100644 --- a/docs_src/security/tutorial005.py +++ b/docs_src/security/tutorial005.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py index 2e8bb3bdb..77be12d88 100644 --- a/docs_src/security/tutorial005_an.py +++ b/docs_src/security/tutorial005_an.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError from typing_extensions import Annotated @@ -59,7 +59,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -70,11 +70,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py index 90781587f..3285f17ed 100644 --- a/docs_src/security/tutorial005_an_py310.py +++ b/docs_src/security/tutorial005_an_py310.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py index a5192d8d6..6239a68d5 100644 --- a/docs_src/security/tutorial005_an_py39.py +++ b/docs_src/security/tutorial005_an_py39.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py index b244ef08e..4952e9253 100644 --- a/docs_src/security/tutorial005_py310.py +++ b/docs_src/security/tutorial005_py310.py @@ -8,7 +8,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -57,7 +57,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -68,11 +68,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py index 8f0e93376..55c666139 100644 --- a/docs_src/security/tutorial005_py39.py +++ b/docs_src/security/tutorial005_py39.py @@ -9,7 +9,7 @@ from fastapi.security import ( SecurityScopes, ) from jwt.exceptions import InvalidTokenError -from passlib.context import CryptContext +from pwdlib import PasswordHash from pydantic import BaseModel, ValidationError # to get a string like this run: @@ -58,7 +58,7 @@ class UserInDB(User): hashed_password: str -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +password_hash = PasswordHash.recommended() oauth2_scheme = OAuth2PasswordBearer( tokenUrl="token", @@ -69,11 +69,11 @@ app = FastAPI() def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) + return password_hash.verify(plain_password, hashed_password) def get_password_hash(password): - return pwd_context.hash(password) + return password_hash.hash(password) def get_user(db, username: str): From b77bbd499d2bddf879ea26ffd9009d77fe7d1067 Mon Sep 17 00:00:00 2001 From: Neizvestnyj Date: Fri, 25 Jul 2025 15:26:59 +0300 Subject: [PATCH 3/4] replace `passlib` to `pwdlib` --- docs/en/docs/how-to/conditional-openapi.md | 2 +- pyproject.toml | 2 -- requirements-tests.txt | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/how-to/conditional-openapi.md b/docs/en/docs/how-to/conditional-openapi.md index bd6cad9a8..af8e3c0b6 100644 --- a/docs/en/docs/how-to/conditional-openapi.md +++ b/docs/en/docs/how-to/conditional-openapi.md @@ -17,7 +17,7 @@ If you want to secure your API, there are several better things you can do, for * Make sure you have well defined Pydantic models for your request bodies and responses. * Configure any required permissions and roles using dependencies. * Never store plaintext passwords, only password hashes. -* Implement and use well-known cryptographic tools, like Passlib and JWT tokens, etc. +* Implement and use well-known cryptographic tools, like pwdlib and JWT tokens, etc. * Add more granular permission controls with OAuth2 scopes where needed. * ...etc. diff --git a/pyproject.toml b/pyproject.toml index 7709451ff..c29159212 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,8 +171,6 @@ junit_family = "xunit2" filterwarnings = [ "error", 'ignore:starlette.middleware.wsgi is deprecated and will be removed in a future release\..*:DeprecationWarning:starlette', - # For passlib - "ignore:'crypt' is deprecated and slated for removal in Python 3.13:DeprecationWarning", # see https://trio.readthedocs.io/en/stable/history.html#trio-0-22-0-2022-09-28 "ignore:You seem to already have a custom.*:RuntimeWarning:trio", # TODO: remove after upgrading SQLAlchemy to a version that includes the following changes diff --git a/requirements-tests.txt b/requirements-tests.txt index b9f2b2b66..627adc7ce 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -9,7 +9,7 @@ flask >=1.1.2,<4.0.0 anyio[trio] >=3.2.1,<5.0.0 PyJWT==2.8.0 pyyaml >=5.3.1,<7.0.0 -passlib[bcrypt] >=1.7.2,<2.0.0 +pwdlib[argon2] >=0.2.1 inline-snapshot>=0.21.1 # types types-ujson ==5.10.0.20240515 From 0ebc05a7858741617d8976c68d802ec1948b0928 Mon Sep 17 00:00:00 2001 From: Neizvestnyj Date: Fri, 25 Jul 2025 17:50:02 +0300 Subject: [PATCH 4/4] use `argon2` in `fake_users_db` `hashed_password` --- docs/en/docs/tutorial/security/oauth2-jwt.md | 2 +- docs/ru/docs/tutorial/security/oauth2-jwt.md | 2 +- docs_src/security/tutorial004.py | 2 +- docs_src/security/tutorial004_an.py | 2 +- docs_src/security/tutorial004_an_py310.py | 2 +- docs_src/security/tutorial004_an_py39.py | 2 +- docs_src/security/tutorial004_py310.py | 2 +- docs_src/security/tutorial005.py | 4 ++-- docs_src/security/tutorial005_an.py | 4 ++-- docs_src/security/tutorial005_an_py310.py | 4 ++-- docs_src/security/tutorial005_an_py39.py | 4 ++-- docs_src/security/tutorial005_py310.py | 4 ++-- docs_src/security/tutorial005_py39.py | 4 ++-- 13 files changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/en/docs/tutorial/security/oauth2-jwt.md b/docs/en/docs/tutorial/security/oauth2-jwt.md index a09af7c1f..5f47f9ed2 100644 --- a/docs/en/docs/tutorial/security/oauth2-jwt.md +++ b/docs/en/docs/tutorial/security/oauth2-jwt.md @@ -120,7 +120,7 @@ And another one to authenticate and return a user. /// note -If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW"`. +If you check the new (fake) database `fake_users_db`, you will see how the hashed password looks like now: `"$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc"`. /// diff --git a/docs/ru/docs/tutorial/security/oauth2-jwt.md b/docs/ru/docs/tutorial/security/oauth2-jwt.md index 68789a3ec..a44deff92 100644 --- a/docs/ru/docs/tutorial/security/oauth2-jwt.md +++ b/docs/ru/docs/tutorial/security/oauth2-jwt.md @@ -113,7 +113,7 @@ pwdlib также имеет функциональность для испол {* ../../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 токенами diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004.py index ec7c818bf..130dc699a 100644 --- a/docs_src/security/tutorial004.py +++ b/docs_src/security/tutorial004.py @@ -20,7 +20,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py index 31c97a0d1..018234e30 100644 --- a/docs_src/security/tutorial004_an.py +++ b/docs_src/security/tutorial004_an.py @@ -21,7 +21,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } diff --git a/docs_src/security/tutorial004_an_py310.py b/docs_src/security/tutorial004_an_py310.py index 807f28990..18ea96bc5 100644 --- a/docs_src/security/tutorial004_an_py310.py +++ b/docs_src/security/tutorial004_an_py310.py @@ -20,7 +20,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } diff --git a/docs_src/security/tutorial004_an_py39.py b/docs_src/security/tutorial004_an_py39.py index d2a254ba0..d3fd29e5a 100644 --- a/docs_src/security/tutorial004_an_py39.py +++ b/docs_src/security/tutorial004_an_py39.py @@ -20,7 +20,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } diff --git a/docs_src/security/tutorial004_py310.py b/docs_src/security/tutorial004_py310.py index b7d5b958b..cd1dcff46 100644 --- a/docs_src/security/tutorial004_py310.py +++ b/docs_src/security/tutorial004_py310.py @@ -19,7 +19,7 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, } } diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py index 710d792cc..1a69c8b62 100644 --- a/docs_src/security/tutorial005.py +++ b/docs_src/security/tutorial005.py @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py index 77be12d88..29c913f69 100644 --- a/docs_src/security/tutorial005_an.py +++ b/docs_src/security/tutorial005_an.py @@ -25,14 +25,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } diff --git a/docs_src/security/tutorial005_an_py310.py b/docs_src/security/tutorial005_an_py310.py index 3285f17ed..07269902e 100644 --- a/docs_src/security/tutorial005_an_py310.py +++ b/docs_src/security/tutorial005_an_py310.py @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } diff --git a/docs_src/security/tutorial005_an_py39.py b/docs_src/security/tutorial005_an_py39.py index 6239a68d5..e2578bf01 100644 --- a/docs_src/security/tutorial005_an_py39.py +++ b/docs_src/security/tutorial005_an_py39.py @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } diff --git a/docs_src/security/tutorial005_py310.py b/docs_src/security/tutorial005_py310.py index 4952e9253..3217d023d 100644 --- a/docs_src/security/tutorial005_py310.py +++ b/docs_src/security/tutorial005_py310.py @@ -23,14 +23,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, } diff --git a/docs_src/security/tutorial005_py39.py b/docs_src/security/tutorial005_py39.py index 55c666139..0e8273141 100644 --- a/docs_src/security/tutorial005_py39.py +++ b/docs_src/security/tutorial005_py39.py @@ -24,14 +24,14 @@ fake_users_db = { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", - "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", "disabled": False, }, "alice": { "username": "alice", "full_name": "Alice Chains", "email": "alicechains@example.com", - "hashed_password": "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm", + "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", "disabled": True, }, }