Django allauth with email as username and multiple sites
Asked Answered
C

1

9

Is it possible to use Django allauth with the authentication method set to 'email' when using it on multiple sites?

I'm aiming to allow a user with the email address [email protected] to create an account at site1.com and a separate account at site2.com.

In order to use email authentication, I need to leave UNIQUE_EMAIL set to True in the settings but this prevents users who already have accounts in one site from creating accounts in the other site.

Centennial answered 6/4, 2018 at 12:20 Comment(0)
D
3

I am assuming you'd like to allow the same email to be registered separately for each of the sites in your Django setup.

Looking at the allauth code; it appears that it is infeasible to do so at the moment, likely because allauth does not take into account site ID as part of the User signup process.

class AppSettings(object):

    class AuthenticationMethod:
        USERNAME = 'username'
        EMAIL = 'email'
        USERNAME_EMAIL = 'username_email'

    class EmailVerificationMethod:
        # After signing up, keep the user account inactive until the email
        # address is verified
        MANDATORY = 'mandatory'
        # Allow login with unverified e-mail (e-mail verification is
        # still sent)
        OPTIONAL = 'optional'
        # Don't send e-mail verification mails during signup
        NONE = 'none'

    def __init__(self, prefix):
        self.prefix = prefix
        # If login is by email, email must be required
        assert (not self.AUTHENTICATION_METHOD ==
                self.AuthenticationMethod.EMAIL) or self.EMAIL_REQUIRED
        # If login includes email, login must be unique
        assert (self.AUTHENTICATION_METHOD ==
                self.AuthenticationMethod.USERNAME) or self.UNIQUE_EMAIL

One way to do this would be as follows: - Keep allauth AUTHENTICATION_METHOD as Username - Store the site alongside the User information, perhaps in a UserProfile or by overriding the User Model. - Make the combination of Email and Site unique. - Override the LoginView such that the user enters email; you can translate the combination of Email, Site to a Unique User account and username; which you can pass on to allauth to perform login.

Assuming you use the Sites framework; your code would look something like this:

from allauth.account.views import LoginView
from django.core.exceptions import ObjectDoesNotExist


class CustomLoginView(LoginView):

    def get_user():
        email = request.POST.get('email')
        current_site = Site.objects.get_current()
        try:
            user = User.objects.get(email=email, site=current_site)
        except ObjectDoesNotExist:
            pass  # Handle Error: Perhaps redirect to signup 
        return user


    def dispatch(self, request, *args, **kwargs):
        user = self.get_user()
        request.POST = request.POST.copy()
        request.POST['username'] = user.username
        return super(CustomLoginView, self).dispatch(request, *args, **kwargs)

Then monkey-patch the LoginView with the custom login view:

allauth.account.views.LoginView = CustomLoginView

Related Reading on setting up a Site FK, and custom auth backends:

Dympha answered 15/4, 2018 at 6:20 Comment(3)
Whilst I think this might work, it doesn't seem like the right thing to do here. It seems like a bit of a hack to force allauth to think it's using the username to login whereas in reality, it's using the email.Centennial
Yup, it is a hack. Like I mentioned, the django user model doesn't associate site with user so there's so natural way of doing this afaikDympha
This method does indeed work but it needs a LOT more effort than just the above. There are quite a few places in the allauth code that filter for email address without (obviously) taking the site into account so a lot of overriding of methods is required and I'm not totally convinced this is the right thing to do. However, in the absence of any response from the allauth guys, this is the only real option, I think.Centennial

© 2022 - 2024 — McMap. All rights reserved.