Search code examples
djangodjango-rest-frameworkdjango-authentication

How do I get the Django login api to work after extending the user object?


I've followed the documentation here to extend my user class, but now my login tests fail. I'm assuming this is due to the extended class not being linked correctly back to the django view that deals with auth.

r = self.client.post('/login/', {'username': 'test@test.com', 'password': 'test'})

returns

b'\n<!doctype html>\n<html lang="en">\n<head>\n  <title>Not Found</title>\n</head>\n<body>\n  <h1>Not Found</h1><p>The requested resource was not found on this server.</p>\n</body>\n</html>\n'

I've set the AUTH_USER_MODEL in my setttings

AUTH_USER_MODEL = 'api.ApiUser'

I can create users in my admin, and login as normal.

models.py

class Company(models.Model):
    """
    Represents a company that has access to the same missions/mission plans/etc.
    """
    id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4)

    name = models.TextField()
    logo = models.ImageField(blank=True)

    def __str__(self):
        return self.name


class UserManager(BaseUserManager):
    def create_user(self, email, password=None):
        """
        Creates and saves a User with the given email, date of
        birth and password.
        """
        if not email:
            raise ValueError('Users must have an email address')

        user = self.model(
            email=self.normalize_email(email),
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, password=None):
        """
        Creates and saves a superuser with the given email, date of
        birth and password.
        """
        user = self.create_user(
            email,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class ApiUser(AbstractBaseUser):
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )
    company = models.ForeignKey(Company, null=True, blank=True, on_delete=models.CASCADE)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        # Simplest possible answer: Yes, always
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        # Simplest possible answer: Yes, always
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        # Simplest possible answer: All admins are staff
        return self.is_admin

What else do I need to do to get the authentication api running again?

Do I need to implement my own view using authenticate?


Solution

  • You can do this

    settings.py

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'rest_framework.authentication.BasicAuthentication',
            'rest_framework.authentication.SessionAuthentication',
            'rest_framework.authentication.TokenAuthentication',
        ]
    }
    
    INSTALLED_APPS = ['rest_framework.authtoken']
    

    urls.py

    from rest_framework.authtoken import views
    urlpatterns += [
        path('api-token-auth/', views.obtain_auth_token)
    ]
    

    curl -X POST -d "username=username&password=password123" http://localhost:8000/api-token-auth/