mirror of https://github.com/tiangolo/fastapi.git
📝 Update `tutorial/security/oauth2-jwt/` to use `pwdlib` with Argon2 instead of `passlib` (#13917)
Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
This commit is contained in:
parent
450a334253
commit
efdafa4361
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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-passlib }
|
||||
## Install `pwdlib` { #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:
|
||||
|
||||
<div class="termy">
|
||||
|
||||
```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 { #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.
|
||||
|
||||
|
|
@ -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"`.
|
||||
|
||||
///
|
||||
|
||||
|
|
@ -264,7 +264,7 @@ Many packages that simplify it a lot have to make many compromises with the data
|
|||
|
||||
It gives you all the flexibility to choose the ones that fit your project the best.
|
||||
|
||||
And you can use directly many well maintained and widely used packages like `passlib` and `PyJWT`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.
|
||||
And you can use directly many well maintained and widely used packages like `pwdlib` and `PyJWT`, because **FastAPI** doesn't require any complex mechanisms to integrate external packages.
|
||||
|
||||
But it provides you the tools to simplify the process as much as possible without compromising flexibility, robustness, or security.
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -172,8 +172,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
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ flask >=1.1.2,<4.0.0
|
|||
anyio[trio] >=3.2.1,<5.0.0
|
||||
PyJWT==2.9.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
|
||||
|
|
|
|||
Loading…
Reference in New Issue