Compare commits

..

13 Commits
1.5.5 ... 1.6.0

3 changed files with 45 additions and 7 deletions

View File

@@ -12,11 +12,20 @@ from ..dependencies import database, cookie
SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
ALGORITHM = "HS256" ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = cookie.OAuth2PasswordBearerWithCookie(tokenUrl="token") oauth2_scheme = cookie.OAuth2PasswordBearerWithCookie(tokenUrl="token")
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
def verify_password(plain_password, hashed_password): def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password) return pwd_context.verify(plain_password, hashed_password)

View File

@@ -4,7 +4,7 @@ from ..dependencies import users_token, database, mail
from ..models import users, email from ..models import users, email
from fastapi.responses import JSONResponse, HTMLResponse from fastapi.responses import JSONResponse, HTMLResponse
from fastapi_mail import MessageSchema, MessageType, FastMail from fastapi_mail import MessageSchema, MessageType, FastMail
import random, os import random, os, bcrypt
router = APIRouter() router = APIRouter()
@@ -68,26 +68,52 @@ async def reset_password(request: Request, key: str | None = None, email: str |
detail="Parameters 'key' and 'email' are required" detail="Parameters 'key' and 'email' are required"
) )
# Vérifier que la clé correspond à celle stockée dans Redis # Récupérer la clé hachée depuis Redis
key_hashed = database.connect_redis.get(email) key_hashed = database.connect_redis.get(email)
if key_hashed is None or key_hashed != key: if key_hashed is None:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, status_code=status.HTTP_400_BAD_REQUEST,
detail="Key is invalid or expired" detail="Invalid or expired reset key"
) )
# Redis stocke les valeurs en `bytes`, donc il faut décoder si nécessaire
if isinstance(key_hashed, bytes):
key_hashed = key_hashed.decode()
# Vérifier que la clé en clair correspond au hash stocké
if not bcrypt.checkpw(key.encode(), key_hashed.encode()):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid reset key"
)
# Afficher la page HTML de réinitialisation du mot de passe # Afficher la page HTML de réinitialisation du mot de passe
return templates.TemplateResponse("reset_password.html", {"request": request, "email": email, "key": key}) return templates.TemplateResponse("reset_password.html", {"request": request, "email": email, "key": key})
@router.post("/password/update", tags=["password"]) @router.post("/password/update", tags=["password"])
async def update_password(request: Request, email: str = Form(...), key: str = Form(...), new_password: str = Form(...)): # Vérification du token dans Redis async def update_password(request: Request, email: str = Form(...), key: str = Form(...), new_password: str = Form(...)): # Vérification du token dans Redis
# Récupérer la clé hachée depuis Redis
key_hashed = database.connect_redis.get(email) key_hashed = database.connect_redis.get(email)
if key_hashed is None or key_hashed.decode() != key: if key_hashed is None:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST, status_code=status.HTTP_400_BAD_REQUEST,
detail="Key is invalid or expired" detail="Invalid or expired reset key"
)
# Redis stocke les valeurs en `bytes`, donc il faut décoder si nécessaire
if isinstance(key_hashed, bytes):
key_hashed = key_hashed.decode()
# Vérifier que la clé en clair correspond au hash stocké
if not bcrypt.checkpw(key.encode(), key_hashed.encode()):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid reset key"
) )
# Recherche de l'utilisateur dans la base de données # Recherche de l'utilisateur dans la base de données

View File

@@ -15,13 +15,16 @@ ACCESS_TOKEN_EXPIRE_MINUTES = 30
async def login_for_access_token( async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
user = users_token.authenticate_user(form_data.username, form_data.password) user = users_token.authenticate_user(form_data.username, form_data.password)
expires_access_token_time = ACCESS_TOKEN_EXPIRE_MINUTES
if form_data.remember_me:
expires_access_token_time=120
if not user: if not user:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password", detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"}, headers={"WWW-Authenticate": "Bearer"},
) )
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token_expires = timedelta(minutes=expires_access_token_time)
access_token = users_token.create_access_token( access_token = users_token.create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires data={"sub": user.username}, expires_delta=access_token_expires
) )