labd / django-cognito-jwt

An Authentication backend for Django Rest Framework for AWS Cognito JWT tokens
MIT License
177 stars 59 forks source link

How to solve `Customized User` clash with `User`? #20

Closed elcolie closed 4 years ago

elcolie commented 5 years ago

Softwares Python: 3.6.8 Django: 2.2.2 OSX: 10.14.2 django-cognito-jwt: 0.0.3

According to #3 I have to customized my User model. Neither single one of the works. I had tried both too.

Case 1: only COGNITO_USER_MODEL

COGNITO_USER_MODEL = "cognitos.User"

Result:

SystemCheckError: System check identified some issues:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
    HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
    HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.
cognitos.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'User.groups'.
    HINT: Add or change a related_name argument to the definition for 'User.groups' or 'User.groups'.
cognitos.User.is_superuser: (models.E006) The field 'is_superuser' clashes with the field 'is_superuser' from model 'cognitos.user'.
cognitos.User.user_permissions: (fields.E304) Reverse accessor for 'User.user_permissions' clashes with reverse accessor for 'User.user_permissions'.
    HINT: Add or change a related_name argument to the definition for 'User.user_permissions' or 'User.user_permissions'.

Case 2: Only AUTH_USER_MODEL

AUTH_USER_MODEL = "cognitos.User"

Result:

SystemCheckError: System check identified some issues:

ERRORS:
cognitos.User.is_superuser: (models.E006) The field 'is_superuser' clashes with the field 'is_superuser' from model 'cognitos.user'.

Case3: Both COGNITO_USER_MODEL and AUTH_USER_MODEL

COGNITO_USER_MODEL = "cognitos.User"
AUTH_USER_MODEL = "cognitos.User"
SystemCheckError: System check identified some issues:

ERRORS:
cognitos.User.is_superuser: (models.E006) The field 'is_superuser' clashes with the field 'is_superuser' from model 'cognitos.user'.

What is the correct approach using this library?

elcolie commented 4 years ago

I found the solution now. I have to startapp with customized User class

import uuid

from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin, UserManager, AbstractUser
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.db import models, IntegrityError
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

class CustomizedUserManager(UserManager):
    def get_or_create_for_cognito(self, payload):
        cognito_id = payload['sub']

        try:
            return self.get(cognito_id=cognito_id)
        except self.model.DoesNotExist:
            pass

        try:
            user = self.create(
                cognito_id=cognito_id,
                email=payload['email'],
                is_active=True)
        except IntegrityError:
            user = self.get(cognito_id=cognito_id)

        return user

class User(AbstractBaseUser, PermissionsMixin):
    username_validator = UnicodeUsernameValidator()

    username = models.CharField(
        _('username'),
        max_length=150,
        unique=True,
        help_text=_('Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.'),
        validators=[username_validator],
        error_messages={
            'unique': _("A user with that username already exists."),
        },
    )
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=150, blank=True)
    email = models.EmailField(_('email address'), blank=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this admin site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    date_joined = models.DateTimeField(_('date joined'), default=timezone.now)

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

    cognito_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    objects = CustomizedUserManager()

And add AUTH_USER_MODEL = 'customized_users.User' to settings.py

jordanmmck commented 4 years ago

Do I really need to create a new app with startapp? I'm trying to get this to work within my existing app. But not having any luck.

SohaibShafiq1 commented 3 years ago

But this error is before migrations. After adding AUTH_USER_MODEL, another error comes.

phydy commented 2 years ago

But this error is before migrations. After adding AUTH_USER_MODEL, another error comes. use , AUTH_USER_MODEL = 'nameOfApp.nameOfModel', should wourk just fine

SunPodder commented 1 year ago

But this error is before migrations. After adding AUTH_USER_MODEL, another error comes. use , AUTH_USER_MODEL = 'nameOfApp.nameOfModel', should wourk just fine

What if I have multiple class inherited from AbstractUser?