Reputation: 783
I am using django-rest-knox
for user authentication and have knox.auth.TokenAuthentication
as the only authentication class. Also, I am using custom user models by extending AbstractBaseUser
. I have email and password as fields for logging in.
According to documentation, when you use token authentication as the only authentication method then you have to override the inbuilt LoginView of knox. I have followed the same method but it does not seem to work out.
views.py
class LoginInterestedUserAPI(LoginView):
def get_user_serializer_class(self):
return LoginInterestedUserSerializer
def post(self, request, format=None):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(request, user)
return super(LoginInterestedUserAPI, self).post(request, format=None)
serializers.py
class LoginInterestedUserSerializer(serializers.ModelSerializer):
class Meta:
model = InterestedUser
fields = ('email', 'password')
def validate(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Unable to log in with the provided credentials")
urls.py
...
urlpatterns = [
path('login', views.LoginInterestedUserAPI.as_view()),
]
When I go to the url /api/login
, I am not getting email and password field to enter my credentials and getting the following output:-
"detail": "Authentication credentials were not provided."
Upvotes: 0
Views: 2137
Reputation: 9
I have fixed that issue in a professional way. The above method will work for you which I have mentioned but now I'm gonna share a professional method with you. So, you have to follow the steps.
Step 1: First of all, create a serializer for login. But inherit Serializer class, not ModelSerialzer class.
class LoginSerializer(serializers.Serializer):
# We're using custom model fields
email = serializers.CharField()
password = serializers.CharField()
def validate(self,data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Incorrect credentials!")
Step 2: Now create a login API in your views.py file.
# Login API
class LoginView(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": AccoutSerilizer(user,context=self.get_serializer_context()).data,
"token": AuthToken.objects.create(user)[1]
})
Step 3: Now just create the endpoint of the login API in the urls.py file. But keep in mind I'm using the Knox framework of Django. So, if you use any other library/framework your method might be different.
Upvotes: 0
Reputation: 783
First issue was in AuthTokenSerializer
in views.py
. AuthTokenSerializer
uses username and password for login, whereas my custom user model was using email and password. Second issue was in LoginInterestedUserSerializer
in which I had used ModelSerializer
and thus subsqeuently inherited create
method due to which I got the error user with this email already exists
. Therefore, serializers.Serializer
should be used. Following are working code snippets:-
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = InterestedUser
fields = ('full_name', 'email')
class LoginInterestedUserSerializer(serializers.Serializer):
email = serializers.EmailField()
password = serializers.CharField(max_length=128)
def validate(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Unable to log in with the provided credentials")
views.py
class LoginView(GenericAPIView):
serializer_class = LoginInterestedUserSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, context={'request': request})
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]
})
Upvotes: 1