mirror of
https://github.com/fastapi-users/fastapi-users.git
synced 2025-11-04 06:37:51 +08:00
Return 403 instead of 401 when a user is known (#705)
* return 403 instead of 401 if user is known * return 403 for unverified users * updated docs
This commit is contained in:
@ -11,7 +11,7 @@ Return a dependency callable to retrieve currently authenticated user, passing t
|
|||||||
|
|
||||||
* `optional`: If `True`, `None` is returned if there is no authenticated user or if it doesn't pass the other requirements. Otherwise, throw `401 Unauthorized`. Defaults to `False`.
|
* `optional`: If `True`, `None` is returned if there is no authenticated user or if it doesn't pass the other requirements. Otherwise, throw `401 Unauthorized`. Defaults to `False`.
|
||||||
* `active`: If `True`, throw `401 Unauthorized` if the authenticated user is inactive. Defaults to `False`.
|
* `active`: If `True`, throw `401 Unauthorized` if the authenticated user is inactive. Defaults to `False`.
|
||||||
* `verified`: If `True`, throw `401 Unauthorized` if the authenticated user is not verified. Defaults to `False`.
|
* `verified`: If `True`, throw `403 Forbidden` if the authenticated user is not verified. Defaults to `False`.
|
||||||
* `superuser`: If `True`, throw `403 Forbidden` if the authenticated user is not a superuser. Defaults to `False`.
|
* `superuser`: If `True`, throw `403 Forbidden` if the authenticated user is not a superuser. Defaults to `False`.
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@ -88,7 +88,7 @@ def protected_route(user: User = Depends(fastapi_users.get_current_active_user))
|
|||||||
|
|
||||||
### `get_current_verified_user`
|
### `get_current_verified_user`
|
||||||
|
|
||||||
Get the current active and verified user. Will throw a `401 Unauthorized` if missing or wrong credentials or if the user is not active and verified.
|
Get the current active and verified user. Will throw a `401 Unauthorized` if missing or wrong credentials or if the user is not active. Will throw a `403 Forbidden` if the user is unverified.
|
||||||
|
|
||||||
```py
|
```py
|
||||||
@app.get("/protected-route")
|
@app.get("/protected-route")
|
||||||
|
|||||||
@ -183,12 +183,13 @@ class Authenticator:
|
|||||||
|
|
||||||
status_code = status.HTTP_401_UNAUTHORIZED
|
status_code = status.HTTP_401_UNAUTHORIZED
|
||||||
if user:
|
if user:
|
||||||
|
status_code = status.HTTP_403_FORBIDDEN
|
||||||
if active and not user.is_active:
|
if active and not user.is_active:
|
||||||
|
status_code = status.HTTP_401_UNAUTHORIZED
|
||||||
user = None
|
user = None
|
||||||
elif verified and not user.is_verified:
|
elif verified and not user.is_verified:
|
||||||
user = None
|
user = None
|
||||||
elif superuser and not user.is_superuser:
|
elif superuser and not user.is_superuser:
|
||||||
status_code = status.HTTP_403_FORBIDDEN
|
|
||||||
user = None
|
user = None
|
||||||
|
|
||||||
if not user and not optional:
|
if not user and not optional:
|
||||||
|
|||||||
@ -191,7 +191,7 @@ class TestGetCurrentVerifiedUser:
|
|||||||
"/current-verified-user",
|
"/current-verified-user",
|
||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
async def test_valid_token_verified_user(
|
async def test_valid_token_verified_user(
|
||||||
self, test_app_client: httpx.AsyncClient, verified_user: UserDB
|
self, test_app_client: httpx.AsyncClient, verified_user: UserDB
|
||||||
@ -253,7 +253,7 @@ class TestGetCurrentVerifiedSuperuser:
|
|||||||
"/current-verified-superuser",
|
"/current-verified-superuser",
|
||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
async def test_valid_token_verified_user(
|
async def test_valid_token_verified_user(
|
||||||
self, test_app_client: httpx.AsyncClient, verified_user: UserDB
|
self, test_app_client: httpx.AsyncClient, verified_user: UserDB
|
||||||
@ -271,7 +271,7 @@ class TestGetCurrentVerifiedSuperuser:
|
|||||||
"/current-verified-superuser",
|
"/current-verified-superuser",
|
||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
async def test_valid_token_verified_superuser(
|
async def test_valid_token_verified_superuser(
|
||||||
self, test_app_client: httpx.AsyncClient, verified_superuser: UserDB
|
self, test_app_client: httpx.AsyncClient, verified_superuser: UserDB
|
||||||
|
|||||||
@ -183,7 +183,7 @@ class TestLogout:
|
|||||||
path, headers={"Authorization": f"Bearer {user.id}"}
|
path, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,7 @@ class TestMe:
|
|||||||
"/me", headers={"Authorization": f"Bearer {user.id}"}
|
"/me", headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
data = cast(Dict[str, Any], response.json())
|
data = cast(Dict[str, Any], response.json())
|
||||||
@ -159,7 +159,7 @@ class TestUpdateMe:
|
|||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
@ -181,7 +181,7 @@ class TestUpdateMe:
|
|||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
||||||
@ -204,7 +204,7 @@ class TestUpdateMe:
|
|||||||
"/me", json={}, headers={"Authorization": f"Bearer {user.id}"}
|
"/me", json={}, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
@ -232,7 +232,7 @@ class TestUpdateMe:
|
|||||||
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
@ -260,7 +260,7 @@ class TestUpdateMe:
|
|||||||
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
@ -288,7 +288,7 @@ class TestUpdateMe:
|
|||||||
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
@ -316,7 +316,7 @@ class TestUpdateMe:
|
|||||||
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
@ -349,7 +349,7 @@ class TestUpdateMe:
|
|||||||
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
"/me", json=json, headers={"Authorization": f"Bearer {user.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
assert after_update.called is False
|
assert after_update.called is False
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
@ -535,8 +535,6 @@ class TestGetUser:
|
|||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
||||||
else:
|
|
||||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
async def test_verified_user(
|
async def test_verified_user(
|
||||||
@ -562,7 +560,7 @@ class TestGetUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
@ -589,7 +587,7 @@ class TestGetUser:
|
|||||||
f"/{user.id}", headers={"Authorization": f"Bearer {superuser.id}"}
|
f"/{user.id}", headers={"Authorization": f"Bearer {superuser.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
@ -633,8 +631,6 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
||||||
else:
|
|
||||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
async def test_verified_user(
|
async def test_verified_user(
|
||||||
@ -661,7 +657,7 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
@ -689,7 +685,7 @@ class TestUpdateUser:
|
|||||||
f"/{user.id}", json={}, headers={"Authorization": f"Bearer {superuser.id}"}
|
f"/{user.id}", json={}, headers={"Authorization": f"Bearer {superuser.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
@ -727,7 +723,7 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
@ -808,7 +804,7 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
@ -847,7 +843,7 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
@ -886,7 +882,7 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
@ -930,7 +926,7 @@ class TestUpdateUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
assert mock_user_db.update.called is True
|
assert mock_user_db.update.called is True
|
||||||
@ -982,8 +978,6 @@ class TestDeleteUser:
|
|||||||
headers={"Authorization": f"Bearer {user.id}"},
|
headers={"Authorization": f"Bearer {user.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
|
||||||
else:
|
|
||||||
assert response.status_code == status.HTTP_403_FORBIDDEN
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
|
|
||||||
async def test_verified_user(
|
async def test_verified_user(
|
||||||
@ -1009,7 +1003,7 @@ class TestDeleteUser:
|
|||||||
headers={"Authorization": f"Bearer {superuser.id}"},
|
headers={"Authorization": f"Bearer {superuser.id}"},
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
@ -1040,7 +1034,7 @@ class TestDeleteUser:
|
|||||||
f"/{user.id}", headers={"Authorization": f"Bearer {superuser.id}"}
|
f"/{user.id}", headers={"Authorization": f"Bearer {superuser.id}"}
|
||||||
)
|
)
|
||||||
if requires_verification:
|
if requires_verification:
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
||||||
else:
|
else:
|
||||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||||
assert response.content == b""
|
assert response.content == b""
|
||||||
|
|||||||
Reference in New Issue
Block a user