From 05f2ef53d225a1eb23a003ecc6fb10b3ba25fba1 Mon Sep 17 00:00:00 2001 From: Oscar Chen Date: Wed, 31 Jul 2024 20:58:23 -0600 Subject: [PATCH 1/2] Add USERNAME_FIELD setting --- docs/settings.md | 3 +++ ninja_simple_jwt/auth/views/api.py | 5 +++-- ninja_simple_jwt/settings.py | 2 ++ ninja_simple_jwt/utils.py | 7 +++++++ tests/test_auth/test_utils.py | 25 +++++++++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 ninja_simple_jwt/utils.py create mode 100644 tests/test_auth/test_utils.py diff --git a/docs/settings.md b/docs/settings.md index a585f26..0505667 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -35,6 +35,9 @@ Same-site policy to be used for refresh token cookie, defaults to `"Strict"`. This is the path set on the cookie for refresh token, this path needs to match the url endpoint you are exposing for web token refresh. Defaults to `"/api/auth/web/token-refresh"`. +### USERNAME_FIELD +This is the field on the User model that is used as the username. Defaults to `"username"`. + ### TOKEN_CLAIM_USER_ATTRIBUTE_MAP A dictionary mapping token claims to corresponding User model attributes. Defaults to the following: ```python diff --git a/ninja_simple_jwt/auth/views/api.py b/ninja_simple_jwt/auth/views/api.py index d379231..a617852 100644 --- a/ninja_simple_jwt/auth/views/api.py +++ b/ninja_simple_jwt/auth/views/api.py @@ -20,6 +20,7 @@ get_refresh_token_for_user, ) from ninja_simple_jwt.settings import ninja_simple_jwt_settings +from ninja_simple_jwt.utils import make_authentication_params mobile_auth_router = Router() web_auth_router = Router() @@ -28,7 +29,7 @@ @mobile_auth_router.post("/sign-in", response=MobileSignInResponse, url_name="mobile_signin") def mobile_sign_in(request: HttpRequest, payload: SignInRequest) -> dict: payload_data = payload.dict() - user = authenticate(username=payload_data["username"], password=payload_data["password"]) + user = authenticate(**make_authentication_params(payload_data)) if user is None: raise AuthenticationError() @@ -53,7 +54,7 @@ def mobile_token_refresh(request: HttpRequest, payload: MobileTokenRefreshReques @web_auth_router.post("/sign-in", response=WebSignInResponse, url_name="web_signin") def web_sign_in(request: HttpRequest, payload: SignInRequest, response: HttpResponse) -> dict: payload_data = payload.dict() - user = authenticate(username=payload_data["username"], password=payload_data["password"]) + user = authenticate(**make_authentication_params(payload_data)) if user is None: raise AuthenticationError() diff --git a/ninja_simple_jwt/settings.py b/ninja_simple_jwt/settings.py index b8dba27..85d7e39 100644 --- a/ninja_simple_jwt/settings.py +++ b/ninja_simple_jwt/settings.py @@ -20,6 +20,7 @@ class NinjaSimpleJwtSettingsDict(TypedDict): WEB_REFRESH_COOKIE_HTTP_ONLY: NotRequired[bool] WEB_REFRESH_COOKIE_SAME_SITE_POLICY: NotRequired[str] WEB_REFRESH_COOKIE_PATH: NotRequired[str] + USERNAME_FIELD: NotRequired[str] TOKEN_CLAIM_USER_ATTRIBUTE_MAP: NotRequired[dict[str, str]] TOKEN_USER_ENCODER_CLS: NotRequired[str] @@ -36,6 +37,7 @@ class NinjaSimpleJwtSettingsDict(TypedDict): "WEB_REFRESH_COOKIE_HTTP_ONLY": True, "WEB_REFRESH_COOKIE_SAME_SITE_POLICY": "Strict", "WEB_REFRESH_COOKIE_PATH": "/api/auth/web/token-refresh", + "USERNAME_FIELD": "username", "TOKEN_CLAIM_USER_ATTRIBUTE_MAP": { "user_id": "id", "username": "username", diff --git a/ninja_simple_jwt/utils.py b/ninja_simple_jwt/utils.py new file mode 100644 index 0000000..80f39ba --- /dev/null +++ b/ninja_simple_jwt/utils.py @@ -0,0 +1,7 @@ +from ninja_simple_jwt.settings import ninja_simple_jwt_settings + + +def make_authentication_params(params: dict) -> dict: + print(params) + print(ninja_simple_jwt_settings.USERNAME_FIELD) + return {ninja_simple_jwt_settings.USERNAME_FIELD: params["username"], "password": params["password"]} diff --git a/tests/test_auth/test_utils.py b/tests/test_auth/test_utils.py new file mode 100644 index 0000000..d9125c6 --- /dev/null +++ b/tests/test_auth/test_utils.py @@ -0,0 +1,25 @@ +from typing import Any + +from django.test import TestCase + +from ninja_simple_jwt.settings import DEFAULTS +from ninja_simple_jwt.utils import make_authentication_params + + +class TestMakeAuthenticationParams(TestCase): + @staticmethod + def merge_settings(**kwargs: Any) -> dict: + return {**DEFAULTS, **kwargs} + + def test_make_default_username_field_params(self) -> None: + with self.settings(): + params = {"username": "username", "password": "password"} + result = make_authentication_params(params) + self.assertEqual(params, result, "Default settings should return the same params.") + + def test_make_customized_username_field_params(self) -> None: + with self.settings(NINJA_SIMPLE_JWT=self.merge_settings(USERNAME_FIELD="email")): + params = {"username": "email", "password": "password"} + expected = {"email": "email", "password": "password"} + result = make_authentication_params(params) + self.assertEqual(expected, result, "Customized settings should return the same params.") From 8e0f9eb080353a277f29cf53187fbabb0b14a8e9 Mon Sep 17 00:00:00 2001 From: Oscar Chen Date: Wed, 31 Jul 2024 21:14:01 -0600 Subject: [PATCH 2/2] Bump dependencies --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 75f578b..0982997 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ -black==23.11.0 -cryptography==41.0.7 +black==24.4.2 +cryptography==43.0.0 Django>=4.2 django-ninja>=1.0 django-stubs[compatible-mypy]==4.2.7