prg.dev
prg.dev

Reputation: 211

Incorrect Credentials

I create custom user model that extends from AbstractBaseUser. I try to connect this model with API using rest framework the register EndPints, getUser and logout is working fine. But when i try to login user it show this message 'Incorrect Credentials'

i try to find the problem and I discover that method authenticate don't work for some resnes

This is My Code

urls.py

from django.urls import path, include
from knox import views as knox_views

# import views
from .views import RegisterAPI, LoginAPI, UserAPI

urlpatterns = [
  path('api/auth', include('knox.urls')),
  path('api/auth/register', RegisterAPI.as_view()),
  path('api/auth/login', LoginAPI.as_view()),
  path('api/auth/user', UserAPI.as_view()),
  path('api/auth/logout', knox_views.LogoutView.as_view(), name='knox-logout'),
]

custom user model

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager

# cerate user manger (replace old user Table with User Table that we cerated)
class UserManager(BaseUserManager):
    def create_user(self, phone, password=None, username=None,is_staff=False, is_admain=False, active=True,**extra_fields):
        if not phone:
            raise ValueError("User must have a phone number")
        if not password:
            raise ValueError("User must have password")

        user = self.model(phone=phone)
        user.set_password(password)
        user.username = username
        user.staff = is_staff
        user.admain = is_admain
        user.active = active
        user.save(using=self.db)
        return user

    def create_staff(self, phone, password=None, username=None,**extra_fields):
        user = self.create_user(phone, password=password,username=username,staff=True)
        return user

    def create_superuser(self, phone, password=None, username=None,**extra_fields):
        user = self.create_user(phone,password=password,username=username)
        user.staff = True
        user.admin = True
        user.save(using=self._db)
        return user

# Cerate User Model the will every user will inherit from it
class User(AbstractBaseUser):
    phone = models.CharField(max_length=9, unique=True)
    username = models.CharField(max_length=60)
    active = models.BooleanField(default=True)   # Can login
    staff = models.BooleanField(default=False)
    admin = models.BooleanField(default=False)
    date_joined = models.DateTimeField(auto_now_add=True)
    date_of_birth = models.DateField(auto_now_add=True)
    USERNAME_FIELD = 'phone'
    REQUIRED_FIELDS = ['username']

    object = UserManager()

    def __str__(self):
        return self.username

    def get_full_name(self):
        return self.phone

    def get_short_name(self):
        return self.username

    def is_staff(self):
        return self.is_staff

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True


    @property
    def is_superuser(self):
        return self.admin

    @property
    def is_active(self):
        return self.active

    @property
    def is_staff(self):
        return self.staff



API.py


from rest_framework import generics, permissions
from rest_framework.response import Response
from knox.models import AuthToken

# import serializers
from .serializers import UserSerializer, RegisterSerializer, LoginSerializer

# Regester API
class RegisterAPI(generics.GenericAPIView):
  serializer_class = RegisterSerializer

  def post(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    user = serializer.save()
    return Response({
      "user": UserSerializer(user, context=self.get_serializer_context()).data,
      "token": AuthToken.objects.create(user)[1]
    })


# Login API
class LoginAPI(generics.GenericAPIView):
  serializer_class = LoginSerializer

  def post(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    user = serializer.validated_data
    return Response({
      "user": UserSerializer(user, context=self.get_serializer_context()).data,
      "token": AuthToken.objects.create(user)[1]
    })

# Get User API
class UserAPI(generics.RetrieveAPIView):
  permission_classes = [permissions.IsAuthenticated,]
  serializer_class = UserSerializer

  def get_object(self):
    return self.request.user

serializers.py


from rest_framework import serializers
from django.contrib.auth import authenticate


# import user Model
from django.contrib.auth import get_user_model

User = get_user_model()

# User Serializer
class UserSerializer(serializers.ModelSerializer):
  class Meta:
    model = User
    fields = ('id', 'phone', 'username', 'active', 'staff', 'admin')


# Register Serializer
class RegisterSerializer(serializers.ModelSerializer):
  class Meta:
    model = User
    fields = ('id', 'phone', 'username', 'active', 'staff', 'admin', 'password')
    extra_kwargs = {'password': {'write_only': True}}

  def create(self, validated_data):
    user = User.object.create_user(validated_data['phone'], validated_data['username'],validated_data['password'])

    return user


# Login Serializer
class LoginSerializer(serializers.Serializer):
  phone = serializers.CharField()
  password = serializers.CharField()

  print("-=-=-=-=-=--=-=-=-=--==-=---")
  def validate(self, data):
    user = authenticate(**data)
    #user = authenticate(phone=data[phone], password=data[password])
    # not comming her ....... why ?!!!!
    print("next !!")
    print("-=-=-=-=-=--=-=-=-=--==-=---")
    if user and user.is_active:
      return user

    raise serializers.ValidationError('Incorrect Credentials')

the API EndPoint return to me this


{
    "non_field_errors": [
        "Incorrect Credentials"
    ]
}

Upvotes: 0

Views: 1337

Answers (2)

Eugine Agolla
Eugine Agolla

Reputation: 1

I got into the same error and found a way to solve it. Probably for my case but hope for many others too. modify your #settings.py file as follows:

settings.py

INSTALLED_APPS = [
    # ... your other apps
    'your_app_name', 
]

AUTH_USER_MODEL = 'your_app_name.'your_custom_user_model' 
AUTH_USER_MODEL = 'mydatabase.Employee'

remember to change 'your_app_name' to be your actual app name

Upvotes: 0

Shakil
Shakil

Reputation: 4630

In your serializer you are validating phone and password field but you are using django-authentication function to validate user. Normally django-authentication takes username and password to validate user but your serializer seems not have username field.

If you want to use authenticate function, first you need to find out the user instance associated with that phone field. One important thing is that as this is an unique field so if user exits surely you want to validate that user.

# Login Serializer
class LoginSerializer(serializers.Serializer):
  phone = serializers.CharField()
  password = serializers.CharField() 


  def validate(self, data):

    try:
        user = User.objects.get(phone=data['phone'])
    except User.DoesNotExist:
        raise serializers.ValidationError('Incorrect Credentials')

    user = authenticate(username=user.username, password=data['password'])

    if user and user.is_active:
      return user

    raise serializers.ValidationError('Incorrect Credentials')

Another important point is that you need to ensure your user is active.

Upvotes: 0

Related Questions