Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django allauth with email as username and multiple sites

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.

like image 332
bodger Avatar asked Apr 06 '18 12:04

bodger


1 Answers

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:

  • How to get unique users across multiple Django sites powered by the "sites" framework?
  • https://docs.djangoproject.com/en/dev/topics/auth/#writing-an-authentication-backend
like image 121
rtindru Avatar answered Sep 28 '22 07:09

rtindru