feat(auth): enhance user authentication with detailed error handling

This commit is contained in:
Davidson Gomes 2025-05-13 09:11:58 -03:00
parent ebbbf62df5
commit b53746dd1f
2 changed files with 39 additions and 13 deletions

View File

@ -191,14 +191,36 @@ async def login_for_access_token(form_data: UserLogin, db: Session = Depends(get
Raises:
HTTPException: If credentials are invalid
"""
user = authenticate_user(db, form_data.email, form_data.password)
user, reason = authenticate_user(db, form_data.email, form_data.password)
if not user:
logger.warning(f"Login attempt with invalid credentials: {form_data.email}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid email or password",
headers={"WWW-Authenticate": "Bearer"},
)
if reason == "user_not_found" or reason == "invalid_password":
logger.warning(f"Login attempt with invalid credentials: {form_data.email}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid email or password",
headers={"WWW-Authenticate": "Bearer"},
)
elif reason == "email_not_verified":
logger.warning(f"Login attempt with unverified email: {form_data.email}")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Email not verified",
)
elif reason == "inactive_user":
logger.warning(f"Login attempt with inactive user: {form_data.email}")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="User account is inactive",
)
else:
logger.warning(
f"Login attempt failed for {form_data.email} (reason: {reason})"
)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid email or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token = create_access_token(user)
logger.info(f"Login successful for user: {user.email}")

View File

@ -374,7 +374,9 @@ def get_user_by_email(db: Session, email: str) -> Optional[User]:
return None
def authenticate_user(db: Session, email: str, password: str) -> Optional[User]:
def authenticate_user(
db: Session, email: str, password: str
) -> Tuple[Optional[User], str]:
"""
Authenticates a user with email and password
@ -384,16 +386,18 @@ def authenticate_user(db: Session, email: str, password: str) -> Optional[User]:
password: User password
Returns:
Optional[User]: Authenticated user or None
Tuple[Optional[User], str]: Authenticated user and reason (or None and reason)
"""
user = get_user_by_email(db, email)
if not user:
return None
return None, "user_not_found"
if not verify_password(password, user.password_hash):
return None
return None, "invalid_password"
if not user.email_verified:
return None, "email_not_verified"
if not user.is_active:
return None
return user
return None, "inactive_user"
return user, "success"
def get_admin_users(db: Session, skip: int = 0, limit: int = 100):