django allauth 在我通过 google 登录完成身份验证后将我发送到 /accounts/social/signup/#

问题描述 投票:0回答:1

我将 djang0-allauth 与我的应用程序集成,但有些东西无法完全正常工作。

每次我尝试通过访问

http://127.0.0.1:8000/accounts/google/login/
并遵循 google 身份验证流程来登录/签名时,我最终都会被发送到
http://127.0.0.1:8000/accounts/social/signup/
,在那里我陷入了某种登录和登录的循环中。

我想我没有正确设置我的设置?或者也许我需要对adapters.py做一些事情

仅就上下文而言,我有一个自定义用户模型,它可能也会产生问题?

设置

"""
Django settings for mywebsite project.

Generated by 'django-admin startproject' using Django 3.2.5.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""

from pathlib import Path
import os
import django_on_heroku
import django_heroku
import cloudinary
import cloudinary_storage
import dj_database_url
from decouple import config
import cloudinary.uploader
import cloudinary.api


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', False)
#env docs https://apple.stackexchange.com/questions/356441/how-to-add-permanent-environment-variable-in-zsh
LOCAL = os.environ.get('ARE_WE_LOCAL', False)

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG_PROPAGATE_EXCEPTIONS = True

ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'produceit.herokuapp.com', 'ateam.productions', 'miliu.co']

# 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',

    'mywebsite',
    'urlshortener.apps.UrlshortenerConfig',
    'action.apps.ActionConfig',
    'file_upload.apps.FileUploadConfig',
    'myusermodel.apps.MyusermodelConfig',

    'django_extensions',
    'bootstrap_modal_forms',
    'widget_tweaks',
    'cloudinary',
    'cloudinary_storage',
    'guardian',

    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    'allauth.socialaccount.providers.google',
    'whitenoise.runserver_nostatic',  # new

    # https://dev.to/mdrhmn/django-google-authentication-using-django-allauth-18f8
]

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',
]

ROOT_URLCONF = 'mywebsite.urls'

PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
# Other settings...
TEMPLATE_DIRS = (
    os.path.join(PROJECT_ROOT, "templates"),
)


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 = 'mywebsite.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 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',
    },
]



# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
#https://learndjango.com/tutorials/django-static-files
STATIC_URL = '/static/'
STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),)
STATIC_ROOT = str(BASE_DIR.joinpath('staticfiles'))
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # new


# https://docs.djangoproject.com/en/3.2/howto/static-files/
#STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
#STATIC_URL = '/static/'
#STATICFILES_DIRS = [    os.path.join(BASE_DIR, "static"),]
#STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# Cloudinary stuff
CLOUDINARY_API_KEY=os.environ.get('CLOUDINARY_API_KEY')
CLOUDINARY_API_SECRET=os.environ.get('CLOUDINARY_API_SECRET')

CLOUDINARY_STORAGE = {
    'CLOUD_NAME': 'ateamproductions',
    'API_KEY': CLOUDINARY_API_KEY,
    'API_SECRET': CLOUDINARY_API_SECRET,
}

cloudinary.config(
    cloud_name="ateamproductions",
    api_key=CLOUDINARY_API_KEY,
    api_secret=CLOUDINARY_API_SECRET
    )

DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
# DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

django_heroku.settings(locals())
#django_on_heroku.settings(locals())


# SECURE_SSL_REDIRECT=True
# SESSION_COOKIE_SECURE=True
# CSRF_COOKIE_SECURE=True
# SECURE_HSTS_SECONDS = 31536000
# SECURE_HSTS_INCLUDE_SUBDOMAINS=True
# SECURE_HSTS_PRELOAD=True

# import django_heroku
# django_heroku.settings(locals())


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',
        }
    }
}




#django
# Debugging in heroku live
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': ('%(asctime)s [%(process)d] [%(levelname)s] ' +
                       'pathname=%(pathname)s lineno=%(lineno)s ' +
                       'funcname=%(funcName)s %(message)s'),
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        }
    },
    'handlers': {
        'null': {
            'level': 'DEBUG',
            'class': 'logging.NullHandler',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        }
    },
    'loggers': {
        'testlogger': {
            'handlers': ['console'],
            'level': 'INFO',
        }
    }
}

COMPRESS_ENABLED = os.environ.get('COMPRESS_ENABLED', False)

SMS_BACKEND = 'sms.backends.dummy.SmsBackend'
TWILIO_ACCOUNT_SID = os.environ.get('TWILIO_ACCOUNT_SID', False)
TWILIO_AUTH_TOKEN = os.environ.get('TWILIO_AUTH_TOKEN', False)
TWILIO_PHONE = os.environ.get('TWILIO_PHONE', False)

自定义用户模型

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

编辑 该问题似乎仅限于当我尝试使用数据库中已存在但不是通过 allauth 流程创建的帐户登录时。

django django-authentication django-allauth
1个回答
0
投票

我在以下场景中遇到了同样的问题:

  • 我的应用程序只有 GitHub 身份验证流程,没有电子邮件/密码身份验证流程。
  • 如果我使用 GitHub flow 进行身份验证。
  • 然后断开 GitHub 帐户与 Django 应用程序的连接 - 只需从
    SocialAccount
    模型中删除用户即可。
  • 如果我尝试重新连接,它会失败并重定向到
    accounts/social/signup

据我了解,在重新连接期间,

django-allauth
检测到已经有用户注册,然后要求我使用现有用户登录,但我无法使用现有用户登录,因为没有这样的选项可以登录in(我需要 GitHub 身份验证才能登录)

这是我使用

signals.py
想出的修复方法:

from allauth.account.utils import perform_login
from allauth.socialaccount.signals import pre_social_login
from django.dispatch import receiver
from allauth.socialaccount.models import SocialAccount
from django.contrib.auth.models import User


def link_to_existing_user(sender, request, sociallogin, **kwargs):
# Check if social login user matches an existing user's username
username = sociallogin.account.extra_data.get('login')

if username:
    # Try to get an existing user by username
    try:
        user = User.objects.get(username=username)
        # Check if this social account is already linked to this user
        existing_social_account = SocialAccount.objects.filter(user=user, provider='github').exists()
        if not existing_social_account:
            sociallogin.connect(request, user)
            # Optionally, directly log in the user
            perform_login(request, user, email_verification='optional')
    except User.DoesNotExist:
        pass  # No matching user found by username

receiver(pre_social_login)(link_to_existing_user)

perform_login
之后,它会重定向到设置中定义的页面:

LOGIN_REDIRECT_URL = "/interests"

这样,我们就绕过了现有用户重定向页面的问题。

当然,您需要在应用程序中启用信号。

© www.soinside.com 2019 - 2024. All rights reserved.