M
M
Mikkkch2020-12-27 17:29:20
Django
Mikkkch, 2020-12-27 17:29:20

Logic of authorization in the form or in the backend?

Hello, in my custom model, the username field is email. Accordingly, in order for the user to successfully log in, it is necessary to rewrite the login logic using email.
There are two ways to do this, but which one is better?

1. You can rewrite AuthenticationForm from django.contrib.auth.forms like this:

def clean(self):
        username = self.cleaned_data.get('username')
        password = self.cleaned_data.get('password')

        if username is not None and password:
            self.user_cache = authenticate(self.request, password=password, **{'email': username})
            if self.user_cache is None:
                raise self.get_invalid_login_error()
            else:
                self.confirm_login_allowed(self.user_cache)

        return self.cleaned_data

Since inside the authenticate function we access the backend, the logic of which looks like this:
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
        try:
            user = UserModel._default_manager.get_by_natural_key(username)
        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

Here it is worth paying attention to the second line. In it, from the dictionary of named arguments, we pull out USERNAME_FIELD, the value of which is just the string 'email.'

2. You can write a custom backend, which I did:
class ConsumerAuthenticationBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        kwargs['email'] = username
        return super().authenticate(request, password=password, **kwargs)

Here we turn to the parent method and make sure that the check for the absence of a username is collected and its method tries to get it from kwargs, where we put our email.

Tell me, please, what is the best way to do it? You don't need to write that you do as you please. I'm interested in best practice.

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question