Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

django social auth don't associate new users correctly #24

Open
aliscie opened this issue Mar 18, 2021 · 3 comments
Open

django social auth don't associate new users correctly #24

aliscie opened this issue Mar 18, 2021 · 3 comments

Comments

@aliscie
Copy link

aliscie commented Mar 18, 2021

I am trying to use social auth in Django in my Django GraphQL API (an alternative to rest api). However, after I created the social auth I created a costume user which make things a bit complicated. Also, it worked at the begging very well but and it created the user called weplutus.1 very well, but later after I added the following settings

#settings.py
#without this code i will get `anonymouseUser`
GRAPHENE = {
    # 'SCHEMA': 'api.schema.schema',
    'MIDDLEWARE': [
        # the problem is here
        'graphql_jwt.middleware.JSONWebTokenMiddleware',
    ],
}

when new users register the social auth associate it with other an existed user even the email is new.

enter image description here

# settings.py

from pathlib import Path
import os

# 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.1/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '*****'


DEBUG = True

ALLOWED_HOSTS = ["*"]  # TODO change this in preduction

CORS_ORIGIN_ALLOW_ALL = True  # TODO change this in preduction

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'graphene_django',
    'corsheaders',
    'api',
    'django_filters',
    'social_django',
]
SITE_ID = 1
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    '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',
]

GRAPHENE = {
    # Note without this you will get anynomus user.
    'MIDDLEWARE': [
        'graphql_jwt.middleware.JSONWebTokenMiddleware',
    ],
}


AUTH_USER_MODEL = 'api.ExtendUser'


# TODO delete this, test if thes send email when creating a new user
# if so try to stop it.
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'


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


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

DATABASES = {
    'default': {
        # When using PostgreSQL, it’s recommended to use the built-in JSONB field (# SOCIAL_AUTH_POSTGRES_JSONFIELD = True) to store the extracted extra_data. To enable it define the setting:
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}
# SOCIAL_AUTH_POSTGRES_JSONFIELD = True

SOCIAL_AUTH_JSONFIELD_ENABLED = True


# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators

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 can be found here http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#authentication-backends

AUTHENTICATION_BACKENDS = [
    'graphql_jwt.backends.JSONWebTokenBackend',
    # provider google-oauth2
    'social_core.backends.google.GoogleOAuth2',
    # 'graphql_auth.backends.GraphQLAuthBackend',
    'django.contrib.auth.backends.ModelBackend',
]

SOCIAL_AUTH_PIPELINE = [
    # Get the information we can about the user and return it in a simple
    # format to create the user instance later. On some cases the details are
    # already part of the auth response from the provider, but sometimes this
    # could hit a provider API.
    'social_core.pipeline.social_auth.social_details',

    # Get the social uid from whichever service we're authing thru. The uid is
    # the unique identifier of the given user in the provider.
    'social_core.pipeline.social_auth.social_uid',

    # Verifies that the current auth process is valid within the current
    # project, this is where emails and domains whitelists are applied (if
    # defined).
    'social_core.pipeline.social_auth.auth_allowed',

    # Checks if the current social-account is already associated in the site.
    'social_core.pipeline.social_auth.social_user',

    # Make up a username for this person, appends a random string at the end if
    # there's any collision.
    'social_core.pipeline.user.get_username',

    # Send a validation email to the user to verify its email address.
    # Disabled by default.
    # 'social_core.pipeline.mail.mail_validation',

    # Associates the current social details with another user account with
    # a similar email address. Disabled by default.
    'social_core.pipeline.social_auth.associate_by_email',

    # Create a user account if we haven't found one yet.
    'social_core.pipeline.user.create_user',

    # Create the record that associates the social account with the user.
    'social_core.pipeline.social_auth.associate_user',

    # Populate the extra_data field in the social record with the values
    # specified by settings (and the default ones like access_token, etc).
    'social_core.pipeline.social_auth.load_extra_data',

    # Update the user record with any changed info from the auth service.
    'social_core.pipeline.user.user_details',
]

SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = "*******"

SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = "*********"

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

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'
MEDIA_URL = '/images/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'static/images')
AUTH_USER_MODEL = 'api.ExtendUser'
ACCOUNT_EMAIL_REQUIRED = False

#modeles.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User, Group, AbstractUser, AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.conf import settings
from django.core.validators import RegexValidator
from django.contrib.auth import get_user_model


StyleTitleFormat = RegexValidator(r'^[^\s]+$', 'spaces not allowed')
# Create your models here.


# class ExtendUser(AbstractBaseUser):
class ExtendUser(AbstractUser, PermissionsMixin):
    username = models.CharField(max_length=30, unique=True)
    email = models.EmailField(max_length=250, unique=True)
    first_name = models.CharField(max_length=30, blank=True, null=True)
    last_name = models.CharField(max_length=30, blank=True, null=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    date_joined = models.DateTimeField(default=timezone.now)
    receive_newsletter = models.BooleanField(default=False)
    birth_date = models.DateTimeField(blank=True, null=True)
    address = models.CharField(max_length=300,  blank=True, null=True)
    city = models.CharField(max_length=30, blank=True, null=True)
    about_me = models.TextField(max_length=500, blank=True, null=True)
    imageUrl = models.URLField(null=True, blank=True)

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email', ]


class Style(models.Model):
    title = models.CharField(max_length=200, validators=[StyleTitleFormat])
    description = models.CharField(max_length=9999999)
    added_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created_date = models.DateTimeField(default=timezone.now)
    who_can_see = models.ManyToManyField(
        settings.AUTH_USER_MODEL, related_name='style_user', blank=True)
    who_can_edite = models.ManyToManyField(
        settings.AUTH_USER_MODEL, related_name='who_can_edite_style', blank=True)

    def __str__(self):
        return self.title


class Post(models.Model):
    # note: posts can have tables as well and they can save it in the description (JSONField)
    # title = models.CharField(max_length=200)
    description = models.CharField(max_length=9999999)
    preBuildStyle = models.ManyToManyField(
        Style, related_name='Styles', blank=True)
    style = models.CharField(max_length=9999999, blank=True)
    # type = ['Paper','post','template','comstume_component']
    postType = models.CharField(max_length=50, blank=True)
    added_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created_date = models.DateTimeField(default=timezone.now)
    who_can_see = models.ManyToManyField(
        settings.AUTH_USER_MODEL, related_name='poster_user', blank=True)
    who_can_edite = models.ManyToManyField(
        settings.AUTH_USER_MODEL, related_name='who_can_edite_Component', blank=True)

    # def __str__(self):
    #     return self.title

# TODO create teams/groups/classes each with admin(creator)+manager(subAdmins)+members
@miodeqqq
Copy link

miodeqqq commented Apr 2, 2021

I'm having a similar issue. Both FB & Google providers assign the same user.

Did you find out what could be the reason ? @aliscie

@miodeqqq
Copy link

miodeqqq commented Apr 2, 2021

I also see that inside TEMPLATES (context_processors) you're missing:

"social_django.context_processors.backends",
"social_django.context_processors.login_redirect" # optional, depends on your logic

but I believe it won't solve your problems, because I have similar config and similar results.

@aliscie
Copy link
Author

aliscie commented Apr 4, 2021

I'm having a similar issue. Both FB & Google providers assign the same user.

Did you find out what could be the reason ? @aliscie

 GRAPHENE = {
-
'MIDDLEWARE': [
     'graphql_jwt.middleware.JSONWebTokenMiddleware',
   ],
 }

AUTHENTICATION_BACKENDS = (
    'graphql_auth.backends.GraphQLAuthBackend',
    'social_core.backends.google.GoogleOAuth2',
    'django.contrib.auth.backends.ModelBackend',
)

also $ pip install django-graphql-auth and $ pip uninstall PyJWT then $ pip install PyJWT==1.7.0
Also the problem could be somewhere else because I recreated my whole project from 0.
Try to use the code in the settings.py,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants