diff --git a/django/contrib/auth/backends.py b/django/contrib/auth/backends.py index 703fd2519dc..05e9bfd7212 100644 --- a/django/contrib/auth/backends.py +++ b/django/contrib/auth/backends.py @@ -8,11 +8,11 @@ class ModelBackend(object): Authenticates against django.contrib.auth.models.User. """ - # TODO: Model, login attribute name and password attribute name should be - # configurable. - def authenticate(self, username=None, password=None): + def authenticate(self, username=None, password=None, **kwargs): + UserModel = get_user_model() + if username is None: + username = kwargs.get(UserModel.USERNAME_FIELD) try: - UserModel = get_user_model() user = UserModel._default_manager.get_by_natural_key(username) if user.check_password(password): return user diff --git a/django/contrib/auth/tests/auth_backends.py b/django/contrib/auth/tests/auth_backends.py index 4fe8d4dfee6..75cec10cf9b 100644 --- a/django/contrib/auth/tests/auth_backends.py +++ b/django/contrib/auth/tests/auth_backends.py @@ -4,7 +4,7 @@ from datetime import date from django.conf import settings from django.contrib.auth.models import User, Group, Permission, AnonymousUser from django.contrib.auth.tests.utils import skipIfCustomUser -from django.contrib.auth.tests.custom_user import ExtensionUser, CustomPermissionsUser +from django.contrib.auth.tests.custom_user import ExtensionUser, CustomPermissionsUser, CustomUser from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured from django.test import TestCase @@ -189,6 +189,24 @@ class CustomPermissionsUserModelBackendTest(BaseModelBackendTest, TestCase): ) +@override_settings(AUTH_USER_MODEL='auth.CustomUser') +class CustomUserModelBackendAuthenticateTest(TestCase): + """ + Tests that the model backend can accept a credentials kwarg labeled with + custom user model's USERNAME_FIELD. + """ + + def test_authenticate(self): + test_user = CustomUser._default_manager.create_user( + email='test@example.com', + password='test', + date_of_birth=date(2006, 4, 25) + ) + authenticated_user = authenticate(email='test@example.com', password='test') + self.assertEqual(test_user, authenticated_user) + + + class TestObj(object): pass diff --git a/docs/ref/contrib/auth.txt b/docs/ref/contrib/auth.txt index 414f4558ee1..b12c99fb91f 100644 --- a/docs/ref/contrib/auth.txt +++ b/docs/ref/contrib/auth.txt @@ -417,9 +417,15 @@ The following backends are available in :mod:`django.contrib.auth.backends`: .. class:: ModelBackend This is the default authentication backend used by Django. It - authenticates using usernames and passwords stored in the - :class:`~django.contrib.auth.models.User` model. + authenticates using credentials consisting of a user identifier and + password. For Django's default user model, the user identifier is the + username, for custom user models it is the field specified by + USERNAME_FIELD (see :doc:`Customizing Users and authentication + `). + It also handles the default permissions model as defined for + :class:`~django.contrib.auth.models.User` and + :class:`~django.contrib.auth.models.PermissionsMixin`. .. class:: RemoteUserBackend