Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use only authenticate for create token #819

Merged
merged 15 commits into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions djoser/auth_backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from djoser.conf import settings


UserModel = get_user_model()


class LoginFieldBackend(ModelBackend):
"""Allows to log in by a different value than the default Django
USERNAME_FIELD."""

def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
if username is None or password is None:
return
get_kwargs = {
settings.LOGIN_FIELD: username,
}
try:
user = UserModel._default_manager.get(**get_kwargs)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
13 changes: 6 additions & 7 deletions djoser/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,17 +117,16 @@ def __init__(self, *args, **kwargs):

def validate(self, attrs):
password = attrs.get("password")
params = {settings.LOGIN_FIELD: attrs.get(settings.LOGIN_FIELD)}
# https://github.com/sunscrapers/djoser/issues/389
# https://github.com/sunscrapers/djoser/issues/429
# https://github.com/sunscrapers/djoser/issues/795
params = {User.USERNAME_FIELD: attrs.get(settings.LOGIN_FIELD)}
self.user = authenticate(
request=self.context.get("request"), **params, password=password
)
if not self.user:
self.user = User.objects.filter(**params).first()
if self.user and not self.user.check_password(password):
self.fail("invalid_credentials")
if self.user and self.user.is_active:
return attrs
self.fail("invalid_credentials")
self.fail("invalid_credentials")
return attrs


class UserFunctionsMixin:
Expand Down
18 changes: 18 additions & 0 deletions docs/source/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,24 @@ Name of a field in User model to be used as login field. This is useful if you
want to change the login field from ``username`` to ``email`` without providing
custom User model.

.. versionchanged:: 2.3.0

As the authentication is happening within the Django's authentication backends, you need a
custom authentication backend that's using ``LOGIN_FIELD`` instead of ``User.USERNAME_FIELD``
for this setting to work as expected.

If you don't want to roll out your own authentication backend, ``LoginFieldBackend`` has been prepared.
It works the same as ``ModelBackend``, but it is using ``LOGIN_FIELD`` instead of ``User.USERNAME_FIELD``.

tomwojcik marked this conversation as resolved.
Show resolved Hide resolved
To make your code backward compatible with previous Djoser versions, add this auth backend to your Django settings:

.. code-block:: python

AUTHENTICATION_BACKENDS = [
"djoser.auth_backends.LoginFieldBackend",
]

Please notice that it is not recommended way of authentication and it may be removed in the future Djoser versions.
**Default**: ``User.USERNAME_FIELD`` where ``User`` is the model set with Django's setting AUTH_USER_MODEL.

.. warning::
Expand Down
Loading
Loading