django-allauth icon indicating copy to clipboard operation
django-allauth copied to clipboard

NotImplementedError at /accounts/google/login/callback/ ...... Unable to find a unique username

Open ghost opened this issue 8 years ago • 8 comments

Here is my models file inside my User_profile app

from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import BaseUserManager,PermissionsMixin
from datetime import *
from django.utils import timezone
from portal import settings
from django.http import HttpResponse

from django.conf import settings
from allauth.account.signals import user_signed_up
from allauth.socialaccount.signals import pre_social_login
from allauth.account.utils import perform_login
from allauth.exceptions import ImmediateHttpResponse
from django.dispatch import receiver
import urllib
from allauth.socialaccount.models import SocialAccount

@receiver(pre_social_login)
def link_to_local_user(sender,request,sociallogin,**kwargs):
	try:
		email_address=sociallogin.account.extra_data["email"]
	except:
		return HttpResponse("Email Required!...")
	users = MyUser.objects.filter(email=email_address)
	if users:
                perform_login(request,users[0],email_verification="optional")
		raise ImmediateHttpResponse(redirect(settings.LOGIN_REDIRECT_URL))



@receiver(user_signed_up)
def user_signed_up_(request, user, sociallogin=None, **kwargs):
	if sociallogin:
		if sociallogin.account.provider == 'google':
			email = sociallogin.account.extra_data['email']

                        # this code is very specific to email eg [email protected]
			firstName = (email.split(".", 1)[0])
			lastName = (email.split(".", 2)[1])
			sub = (email.split(".", 3)[2])
			sub1 = (sub.split("@", 1)[0])
			dept = sub1[:3]
			year = sub1[3:]
			dom = (sub.split("@", 1)[1])
			try:
				chk_user_exist = StudentProfile.objects.get(user_key__email=email)
			except StudentProfile.DoesNotExist:
				create_social_profile = StudentProfile(user_key__email=email, firstName=firstName, lastName=lastName, dept=dept, year=year)
				create_social_profile.save()
				get_myuser = MyUser.objects.get(email=create_social_profile.user_key.email)
				get_myuser.category = "student"
				
				get_myuser.save()


class StudentProfile(models.Model):
	id = models.AutoField(primary_key=True)
	user_key = models.ForeignKey(settings.AUTH_USER_MODEL)
	firstName = models.CharField(max_length=40)
	lastName = models.CharField(max_length=40)
	dept = models.CharField(max_length=40)
	year = models.CharField(max_length=40)
	bio = models.CharField(max_length=100)

	def __unicode__(self):              # __unicode__ on Python 2
			return '%s' % self.user_key.email


class AuthUserManager(BaseUserManager):
	def create_user(self, username, email, category, password=None,):
		if not username:
			raise ValueError("User must have a username")

		user = self.model(username=self.normalize_email(username),)
		user.is_active = True
		user.set_password(password)
		user.email = email
		user.category = category
		
		user.save(using=self._db)
		return user

	def create_superuser(self, username, email, category, password,):
		user = self.create_user(username=username, email=email, category=category, password=password,)
		user.is_staff = True
		user.is_superuser = True
		user.save(using=self._db)
		return user


class MyUser(AbstractBaseUser, PermissionsMixin):
	username = models.EmailField(unique=True)
	email = models.EmailField(unique=True)
	category = models.CharField(max_length=20, default='individual')   # 0 for Alumni 1 for Student 2 for Faculty
	objects = AuthUserManager()
	is_active = models.BooleanField(default=True, null=False)
	is_staff = models.BooleanField(default=False, null=False)
	date_joined = models.DateTimeField(null=True, blank=True)
	last_message_checked = models.DateTimeField(default=timezone.now)
	USERNAME_FIELD = 'username'
	REQUIRED_FIELDS = ['email', 'category']
	
	def get_full_name(self):
		user = self.username
		return user

	def get_short_name(self):
		return self.username

	def __unicode__(self):              # __unicode__ on Python 2
		return '%s' % self.username`

and here is my settings.py

import os


BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))



SECRET_KEY =

DEBUG = True

ALLOWED_HOSTS = []




INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.sites',
    
    # User profile app
    'User_profile.apps.UserProfileConfig',

    # allauth apps
    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.google',
    
]
AUTH_USER_MODEL = 'User_profile.MyUser'
LOGIN_URL='/login/'
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'portal.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'portal.wsgi.application'



DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}



AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]



LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True



STATIC_URL = '/static/'

AUTHENTICATION_BACKENDS = (


    'django.contrib.auth.backends.ModelBackend',

    'allauth.account.auth_backends.AuthenticationBackend',

)

SITE_ID = 1

SOCIALACCOUNT_QUERY_EMAIL = True
SOCIALACCOUNT_AUTO_SIGNUP=True
SOCIALACCOUNT_EMAIL_REQUIRED = True

LOGIN_REDIRECT_URL = '/'
SOCIALACCOUNT_PROVIDERS = \
{
    'google':
        {'SCOPE': ['profile', 'email'],
        'AUTH_PARAMS': {'access_type': 'online'}}

}

I am trying to implement custom user model in allauth and whenever i try to login using the provider as in this case Google i get the following error

Environment:

Request Method: GET Request URL: http://127.0.0.1:8000/accounts/google/login/callback/?state=SLxfbWOi3scH&code=4/udlpJs8haAT5ymA3PbG_3qzBnqS0ltyjDwBvUzfCbfw

Django Version: 1.11.1 Python Version: 3.6.1 Installed Applications: ['django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', 'User_profile.apps.UserProfileConfig', 'allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google'] Installed Middleware: ['django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\django\core\handlers\exception.py" in inner 41. response = get_response(request)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\django\core\handlers\base.py" in _get_response 187. response = self.process_exception_by_middleware(e, request)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\django\core\handlers\base.py" in _get_response 185. response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\socialaccount\providers\oauth2\views.py" in view 73. return self.dispatch(request, *args, **kwargs)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\socialaccount\providers\oauth2\views.py" in dispatch 143. return complete_social_login(request, login)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\socialaccount\helpers.py" in complete_social_login 153. return _complete_social_login(request, sociallogin)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\socialaccount\helpers.py" in _complete_social_login 175. ret = _process_signup(request, sociallogin)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\socialaccount\helpers.py" in _process_signup 46. get_adapter(request).save_user(request, sociallogin, form=None)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\socialaccount\adapter.py" in save_user 80. get_account_adapter().populate_username(request, u)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\account\adapter.py" in populate_username 217. 'user']))

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\account\adapter.py" in generate_unique_username 220. return generate_unique_username(txts, regex)

File "C:\Users\Dell\Documents\Project\env_portal\lib\site-packages\allauth\utils.py" in generate_unique_username 114. raise NotImplementedError('Unable to find a unique username')

Exception Type: NotImplementedError at /accounts/google/login/callback/ Exception Value: Unable to find a unique username

ghost avatar Jun 30 '17 16:06 ghost

+1

rotherfuchs avatar Dec 25 '17 19:12 rotherfuchs

the same error has just got

vadim-serdiuk-nextiva avatar Feb 05 '18 19:02 vadim-serdiuk-nextiva

+1 Same error but with facebook.

renatonankran avatar Jul 02 '18 22:07 renatonankran

+1 Same with Facebook

slavengoose avatar Nov 14 '18 19:11 slavengoose

I was getting same error but with my custom user (email instead of username), I followed this https://django-allauth.readthedocs.io/en/latest/advanced.html#custom-user-models

magnizide avatar Oct 02 '19 02:10 magnizide

Try setting ACCOUNT_USER_MODEL_USERNAME_FIELD to None.

DStape avatar Dec 22 '20 21:12 DStape

I'm in the same situation as @magnizide.

Setting ACCOUNT_USER_MODEL_USERNAME_FIELD to None, as advised by @DStape, did the trick, but I'm uncomfortable with this state of affairs.

The documentation doesn't explicitly state that None is a possible value, and the consequences of choosing None are unknown.

ngirard avatar May 04 '21 12:05 ngirard

@DStape it looked very promising - the tutorial that I was following did the same thing, too - but it didn't change anything in my case, same exact exception is thrown

alexakarpov avatar Jan 31 '22 17:01 alexakarpov

The following combination seems to work without changing much:

ACCOUNT_USER_MODEL_USERNAME_FIELD = None
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = "email"
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_EMAIL_VERIFICATION = "mandatory"

Olfredos6 avatar Nov 16 '22 07:11 Olfredos6

Bypass Allauth Default Account Adapter while it raise , you modify it to check username exist and else ....

sharad740 avatar Nov 16 '22 16:11 sharad740

What is happening here is that username is not a username, it is a models.EmailField(). Meaning, it can only be populated with valid emails. Now, allauth has a setting ACCOUNT_USERNAME_VALIDATORS which, by default, is populated with the validators attached to the field. The clean_username() adapter method uses these as part of the unique username generation logic. But, given that allauth is attempting to construct usernames, not email addresses, all username candidates are rejected. If your model does not have a user model, please indicate so by using ACCOUNT_USER_MODEL_USERNAME_FIELD = None as documented over at Custom User Models.

pennersr avatar Nov 16 '22 19:11 pennersr