#django #django-allauth
#джанго #джанго-аллаут
Вопрос:
Я интегрировал django-allauth с моим приложением Django, но что-то не работает полностью:
Проблема
- Если пользователь, у которого нет учетной записи в моей базе данных, попытается зарегистрироваться с помощью процесса google allauth, после процесса аутентификации он будет успешно отправлен на домашнюю страницу (за фильтром входа в систему).
- Однако, если пользователь , у которого уже есть учетная запись в моей базе данных (созданная вручную), попытается войти в систему с помощью аутентификации Google, посетив
/accounts/google/login/
ее, после процесса аутентификации она будет отправлена на/accounts/social/signup/
(странную страницу, которая есть у django-allauth). Забавно, что пользователь вошел в систему, и если он попытается получить доступ к домашней странице, он сможет, и все работает. Так что это просто перенаправление, которое нарушено.
Я сузил это до того факта, что электронная почта пользователя уже существует, но с ней не связана социальная учетная запись.
Установка
У меня есть пользовательская модель пользователя, в которой электронная почта является основным уникальным идентификатором пользователя.
from django.contrib.auth.base_user import BaseUserManager from django.db import models from django.contrib.auth.models import AbstractUser from django.utils.translation import ugettext_lazy as _ class CustomUserManager(BaseUserManager): """ Custom user model manager where email is the unique identifiers for authentication instead of usernames. """ def create_user(self, email, password, **extra_fields): """ Create and save a User with the given email and password. """ if not email: raise ValueError(_('The Email must be set')) email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save() return user def create_superuser(self, email, password, **extra_fields): """ Create and save a SuperUser with the given email and password. """ extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) extra_fields.setdefault('is_active', True) if extra_fields.get('is_staff') is not True: raise ValueError(_('Superuser must have is_staff=True.')) if extra_fields.get('is_superuser') is not True: raise ValueError(_('Superuser must have is_superuser=True.')) return self.create_user(email, password, **extra_fields) class CustomUser(AbstractUser): username = None email = models.EmailField(_('email address'), unique=True) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] objects = CustomUserManager() def __str__(self): return self.email
I have an Adapter that I hoped was going to solve my problem but didn’t (so I did something wrong on it)
class MySocialAccountAdapter(DefaultSocialAccountAdapter): def pre_social_login(self, request, sociallogin): user = sociallogin.user if user.id: return try: # if user exists, connect the account to the existing account and login customer = CustomUser.objects.get(email=user.email) sociallogin.state['process'] = 'connect' #sociallogin.connect(request, user) perform_login(request, customer, 'none') except CustomUser.DoesNotExist: pass
my settings
... # Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.sites', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'allauth', 'allauth.account', 'allauth.socialaccount', 'allauth.socialaccount.providers.google', 'whitenoise.runserver_nostatic', # new ] MIDDLEWARE = [ #'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', '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', ] ... 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', }, ] AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', 'allauth.account.auth_backends.AuthenticationBackend', 'guardian.backends.ObjectPermissionBackend', ] SITE_ID = 3 LOGIN_REDIRECT_URL = '/' ACCOUNT_ADAPTER = 'myusermodel.adapter.MyAccountAdapter' # Additional configuration settings SOCIALACCOUNT_QUERY_EMAIL = True ACCOUNT_LOGOUT_ON_GET = True ACCOUNT_UNIQUE_EMAIL = True ACCOUNT_EMAIL_REQUIRED = True ACCOUNT_USER_MODEL_USERNAME_FIELD = None ACCOUNT_USERNAME_REQUIRED = False ACCOUNT_AUTHENTICATION_METHOD = 'email' AUTH_USER_MODEL = 'myusermodel.CustomUser' SOCIALACCOUNT_PROVIDERS = { 'google': { 'SCOPE': [ 'profile', 'email', ], 'AUTH_PARAMS': { 'access_type': 'online', } } } ...
Ответ №1:
ИСПРАВЛЕНО!
Это мой новый адаптер, все было так просто!
from allauth.account.adapter import DefaultAccountAdapter from allauth.socialaccount.adapter import DefaultSocialAccountAdapter from django.shortcuts import redirect, reverse from myusermodel.models import CustomUser class MyAccountAdapter(DefaultAccountAdapter): def get_login_redirect_url(self, request): print('I am entering get_login_redirect_url') if 'team_membership_project_id' in request.session: parameters = {} parameters['invitation_id'] = request.session['invitation_id'] path = reverse('action:accept_invitation', urlconf=None, args=None, kwargs=parameters) return path path = '/' return path def is_open_for_signup(self, request): """ Checks whether or not the site is open for signups.Next to simply returning True/False you can also intervene the regular flow by raising an ImmediateHttpResponse. (Comment reproduced from the overridden method.) """ return True class MySocialAccountAdapter(DefaultSocialAccountAdapter): def pre_social_login(self, request, sociallogin): user = CustomUser.objects.filter(email=sociallogin.user.email).first() if user and not sociallogin.is_existing: sociallogin.connect(request, user)