0

I'm writing a custom backend for authenticating users by their email address instead of username. I've already written a custom User model that inherits from AbstractUser:

class User(AbstractUser):
    email = models.EmailField(
        _('email address'),
        max_length=150,
        unique=True,
        primary_key=True,
        help_text=_('Required. 150 characters of fewer. Must be a valid email address.'),
        error_messages={
            'unique':_("A user with that email address already exists."),
        },
    )

As you can see, I've made the email-field unique, and also, a primary key.

I'm following the docs for how to write the backend, and I've read this:

The Django admin is tightly coupled to the Django User object. The best way to deal with this is to create a Django User object for each user that exists for your backend (e.g., in your LDAP directory, your external SQL database, etc.) You can either write a script to do this in advance, or your authenticate method can do it the first time a user logs in.

It says that I should create a Django User object (which I'm guessing is the default User object django.contrib.auth.models.User) for each user in my backend.

Question 1: If a backend is a class that implements get_user(user_id) and authenticate(request, **credentials) (this is said in the docs), how can a backend contain users? What is meant by "user in my backend"?

Question 2: Do I really have to create a normal Django User object, if my cutsom user objects are subclasses of AbstractUser? They're pretty much identical to django.contrib.auth.models.User, except that the email-field is primary key and unique.

Sahand
  • 7,980
  • 23
  • 69
  • 137
  • 1
    You need just a custom authentication backend, not a whole model. Refer to https://stackoverflow.com/a/37332393/7654934. – N. Ivanov Dec 15 '17 at 11:35
  • 1
    The `email` field should definitely be unique if you want to use it to log-in, but you may want to rethink using it as the `primary_key`. This might make it tricky for users to change email address. – Alasdair Dec 15 '17 at 11:46
  • 1
    The default authentication backend supports a custom user model with `USERNAME_FIELD = 'email'`. I would do that, and then there's no need for a custom authentication backend. – Alasdair Dec 15 '17 at 11:54
  • Alasdair, isn't the example in the docs several orders of magnitude more difficult than the previous question that Ivanov linked to? – Sahand Dec 15 '17 at 11:57
  • 1
    I probably shouldn't have linked to [that example](https://docs.djangoproject.com/en/2.0/topics/auth/customizing/#a-full-example), I've removed it from my answer now. That example is using `AbstractBaseUser`, not `BaseUser`, so more code is required. See [this other](https://stackoverflow.com/a/43209322/113962) answer from the question @N.Ivanov linked to. – Alasdair Dec 15 '17 at 12:11

1 Answers1

2

If you have USERNAME_FIELD = 'email' for your custom model, then you shouldn't have to write a custom authentication backend. The default ModelBackend will handle logging in with email.

When Django talks about users in your backend, it means the LDAP directory or external database that contains those uses, not your backend class that accesses these. If you have a custom user model then the get_user model should return that, and not the User model. However, as I said already, it sounds like it isn't actually necessary for you to write your own authentication backend.

Alasdair
  • 298,606
  • 55
  • 578
  • 516