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

Is it possible to login by email, not username ? #389

Closed
deinega opened this issue May 24, 2019 · 19 comments
Closed

Is it possible to login by email, not username ? #389

deinega opened this issue May 24, 2019 · 19 comments

Comments

@deinega
Copy link

deinega commented May 24, 2019

I would like to use /token/login/ endpoint, but it accepts only username.
Is it possible to login by email instead ?

@nbap
Copy link

nbap commented May 24, 2019

It is but it's not directly related with Djoser.
You need to extend both UserModel and UserManager to use email as username. You may want to use django-username-email which is pretty straightforward lib or take a look at the lib's source code to get an idea on how to achieve this.

Please, see also: https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#substituting-a-custom-user-model

@deinega
Copy link
Author

deinega commented May 24, 2019

I see... I already have django running in production, and this is not as easy to do according to:
https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#changing-to-a-custom-user-model-mid-project

I found that this project offers login by email (if you use ACCOUNT_USERNAME_REQUIRED=False):
https://django-rest-auth.readthedocs.io/en/latest/api_endpoints.html

Maybe, it would be nice if Djoser will also have this possibility...

@nbap
Copy link

nbap commented May 24, 2019

I see... I already have Django running in production, and this is not as easy to do according to:

Yeah, it's not recommended when you already have a system running in production.

I found that this project offers login by email (if you use ACCOUNT_USERNAME_REQUIRED=False):

If you do not intend to replace the username field with email in your models and just want to be able to login using the email address, it is relatively easy to write a custom view to achieve this.

@deinega
Copy link
Author

deinega commented May 24, 2019

I see.
I have looked at Djoser other endpoints, and they are using User.USERNAME_FIELD which is username by default (not email).
So, if I am running Django in production and I can't change User.USERNAME_FIELD, then it will need to write all these endpoints by myself, instead of relying on Djoser (since I would like to use email instead of username) ? So, I can't really use Djoser...

@nbap
Copy link

nbap commented May 24, 2019

Well, regarding the original question you mentioned only the endpoint /token/login/ so that would be a matter of replacing only the classes TokenCreateSerializer and TokenCreateView. Now if you want to use email as username system-wide then you don't have much of alternative.

@deinega
Copy link
Author

deinega commented May 25, 2019

I see, ok, thank you, it is very good explanation !
It is interesting that for these guys it is still possible to use email even with default UserModel:
https://django-rest-auth.readthedocs.io/en/latest/api_endpoints.html
Maybe, they do something differently...

@nbap
Copy link

nbap commented May 25, 2019

I see, ok, thank you, it is very good explanation !

You are welcome.

It is interesting that for these guys it is still possible to use email even with default UserModel:

To be honest, I did a search on their repository and didn't find any reference to the variable ACCOUNT_USERNAME_REQUIRED that you mentioned.

@deinega
Copy link
Author

deinega commented May 25, 2019

This variable is taken from django-allauth which you can install following Registration (optional) paragraph from:
https://django-rest-auth.readthedocs.io/en/latest/installation.html
After using ACCOUNT_USERNAME_REQUIRED = False, their /rest-auth/login/ endpoint does not require username anymore.
I tried to apply ACCOUNT_USERNAME_REQUIRED = False with djoser (I have django-allauth installed already), and username is still required.

@nbap
Copy link

nbap commented May 25, 2019

The setting ACCOUNT_USERNAME_REQUIRED is used as part of the configuration when you want to extend the UserModel to replace the username field with the email as they explain here: https://github.com/pennersr/django-allauth/blob/ae5d9e15d13ead2a25feac67a1206a97a28eb37b/docs/advanced.rst

In the login endpoint, it probably only substitutes the lookup field when logging in. Internally you still have the username and email fields and username is still the default in the AbstractBaseUser.USERNAME_FIELD

@deinega
Copy link
Author

deinega commented May 25, 2019

Yeah, maybe this is what it does in login endpoint.
But I don't need to extend manually UserModel in order to be able to login via email. I can login via email just by setting ACCOUNT_USERNAME_REQUIRED=False.
Djoser is less flexible in this sense, and I need to create my own view to achieve this (if I don't want to extend manually UserModel)...

@dekoza
Copy link
Contributor

dekoza commented May 25, 2019

Thank you, @nbap for handling this issue 👍

Djoser has relied on User.USERNAME_FIELD for login purposes (see djoser.serializers.TokenCreateSerializer.__init__). This will change in djoser-2.0 in favor of LOGIN_FIELD setting.

dekoza added a commit that referenced this issue May 25, 2019
@dekoza dekoza closed this as completed May 25, 2019
dekoza added a commit to dekoza/djoser that referenced this issue May 25, 2019
dekoza added a commit that referenced this issue May 25, 2019
@superibk
Copy link

Can't figure out a way to pass the User.EMAIL_FIELD to LOGIN_FIELD in Django setting .
I tried this

from django.apps import apps
from django.conf import settings as django_settings

auth_module, user_model = django_settings.AUTH_USER_MODEL.rsplit(".", 1)
User = apps.get_model(auth_module, user_model)

 DJOSER = {
      'SEND_ACTIVATION_EMAIL':False,
       'LOGIN_FIELD': User.EMAIL_FIELD,
 }

But it seems the user model has not been loaded at this point, how can I pass in this parameter

@howiezhao
Copy link

same issue @superibk

@ghost
Copy link

ghost commented Sep 21, 2020

https://stackoverflow.com/questions/37332190/django-login-with-email

@TulsiSwami
Copy link

Try this:

DJOSER = {
      'SEND_ACTIVATION_EMAIL':False,
       'LOGIN_FIELD': 'email'  # <-- Name of a field in User model to be used as login field
 }

@jis0324
Copy link

jis0324 commented Apr 12, 2021

@TulsiSwami is Right.
image
image

@chizom
Copy link

chizom commented May 11, 2021

when I set
"LOGIN_FIELD": "email", to "username"It gives me the following error when I call the{{api}}/account/users/` api
What do I do?

Screenshot 2021-05-11 at 15 26 30

@captbilard
Copy link

@Chiz0m Djoser uses the username by default for /users/ so you don't necessarily have to include that in the configuration.

@wajdifoothill
Copy link

wajdifoothill commented Sep 11, 2023

The issue is not in djoser, the default django/contrib/auth/models that djoser serializer depends on.
Resolve
you should customize your User manager like in signup I want to use only email and password not username, s I customize my User Manager as follow:

  class CustomUserManager(UserManager):
  
      def _create_user(self, email, password, **extra_fields):
          email = self.normalize_email(email)
          user = self.model(email=email, **extra_fields)
          user.password = make_password(password)
          user.save(using=self._db)
          return user
  
      def create_user(self, email, password=None, **extra_fields):
          extra_fields.setdefault("is_staff", False)
          extra_fields.setdefault("is_superuser", False)
          return self._create_user(email, password, **extra_fields)

Here is default User manager:

  class UserManager(BaseUserManager):
  
      use_in_migrations = True
  
      def _create_user(self, username, email, password, **extra_fields):
          if not username:
              raise ValueError("The given username must be set")
          email = self.normalize_email(email)
          # Lookup the real model class from the global app registry so this
          # manager method can be used in migrations. This is fine because
          # managers are by definition working on the real model.
          GlobalUserModel = apps.get_model(
              self.model._meta.app_label, self.model._meta.object_name
          )
          username = GlobalUserModel.normalize_username(username)
          user = self.model(username=username, email=email, **extra_fields)
          user.password = make_password(password)
          user.save(using=self._db)
          return user
  
      def create_user(self, username, email=None, password=None, **extra_fields):
          extra_fields.setdefault("is_staff", False)
          extra_fields.setdefault("is_superuser", False)
          return self._create_user(username, email, password, **extra_fields)

Done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants