0

Using Django REST Framework, I've created a custom user that authenticates using a phone number instead of username. I can successfully create a superuser using create_superuser and the superuser does appear in the database. However, when I enter the login page, I can't login with the phone number and password I've chosen (yes, I've double and triple checked the password/phone number and tried multiple different passwords/phone numbers). Here is (a stub of) my custom user class' models.py file:

class User(AbstractBaseUser, PermissionsMixin):
    phone_regex = RegexValidator(
    regex=r'^\+?1?\d{9,15}$',
    message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")

    phone_number = models.CharField(_('phone number'), unique=True, validators=[phone_regex], max_length=17, blank=True)
    .
    .
    .
    objects = UserManager()
    USERNAME_FIELD = 'phone_number'
    REQUIRED_FIELDS = ['first_name', 'last_name']

serializers.py:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'phone_number', 'groups')

managers.py:

class UserManager(BaseUserManager):
    use_in_migrations = True

    def _create_user(self, phone_number, password, **extra_fields):
        """
        Creates and saves a User with the given phone number and password.
        """
        if not phone_number:
            raise ValueError('The phone number must be set')
        user = self.model(phone_number=phone_number, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, phone_number, password=None, **extra_fields):
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(phone_number, password, **extra_fields)

    def create_superuser(self, phone_number, password, **extra_fields):
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(phone_number, password, **extra_fields)

urls.py:

from django.conf.urls import url, include
from rest_framework import routers
from customauth import views

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    url(r'^', include(router.urls)),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]

settings.py:

AUTH_USER_MODEL = 'customauth.User'

What am I missing or doing wrong?

NB: Not a duplicate of this question, which deals with using a UserProfile class, not subclassing AbstractBaseUser.

4
  • Have you set up the scheme: django-rest-framework.org/api-guide/authentication/… ? Commented Oct 27, 2018 at 21:55
  • @ruddra how should I set it up exactly? Should I use the DEFAULT_AUTHENTICATION_CLASSES indicated at the link? Commented Oct 27, 2018 at 22:05
  • yes, as per documentation Commented Oct 27, 2018 at 22:07
  • @ruddra doesn't work Commented Oct 27, 2018 at 22:08

1 Answer 1

1

One way of doing is to override authentication backend like this:

class CustomAuthBackend(object):
    def authenticate(self, request):
        phone = request.POST.get('username') 
        password = request.POST.get('password')

        if not phone:
            return None
        try:
            user = CustomUser.objects.get(phone=phone)
            if user.check_password(password):
                return user
        except CustomUser.DoesNotExist:
            # exception handling
            return None
        return None

And update your settings.py with:

AUTHENTICATION_BACKENDS = ['path.to.your.CustomAuthBackend']
Sign up to request clarification or add additional context in comments.

7 Comments

This gives me a authenticate() missing 1 required positional argument: 'password' error because somewhere in the django-rest-framework code, it calls authenticate without a password field
still nothing :( @ruddra
If it helps, for whatever reason when I create an account on the site (e.g. not via the console), it doesn't ask for a password
sorry, my bad. I had made a mistake in the answer
that gives, get_user() takes 1 positional argument but 2 were given
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.