DJANGO + JWT TOKEN AUTHENTICATION - django

So I was trying to build a backend for my Android application. I was trying to apply a login procedure that works with JWT Token
This is what I have done :
I have made a custom User model.
Customize my superuser to take phone number and password, instead of username and password
I have successfully created superuser and store it in my database (using postgreSQL).
I have also customize my token claims and response as seen in my serializers.py of class LoginSerializer.
However, I encounter some problem after what I did :
Right now, after customizing my user model, I was not able to login to Django administration with my new custom made User model, even though I have succesfully created a superuser.
I still can't get the token even after I have made a customization for my token claims, with the success superuser account I just created.
Here are some of the error message :
Here are the some of the files attatched below :
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser,BaseUserManager
from django.utils.translation import ugettext_lazy as _
from phone_field import PhoneField
class RegisterUserManager(BaseUserManager):
def create_user(self, phone_number,password):
if not phone_number:
raise ValueError('The phone number must be set')
user = self.model(
phone_number=phone_number,
password = password,)
user.save(using = self._db)
return user
def create_superuser(self,phone_number,password, **extra_fields):
user = self.create_user(
phone_number,
password = password
)
user.is_admin = True
user.save(using= self._db)
return user
class RegisterUser(AbstractBaseUser):
first_name = models.CharField(name = 'first_name',max_length=255,default = '')
last_name = models.CharField(name='last_name', max_length=255,default = '')
email = models.EmailField(name='email', max_length = 255)
phone_number = PhoneField(name='phone_number',unique=True)
birthday = models.DateField(name ='birthday',null= True)
nickname = models.CharField(max_length=100,name = 'nickname')
is_active = models.BooleanField(default = True)
is_admin = models.BooleanField(default= False)
last_login = models.DateTimeField(auto_now= True)
USERNAME_FIELD = 'phone_number'
REQUIRED_FIELDS = []
objects = RegisterUserManager()
def __str__(self):
return self.phone_number
def has_perm(self, perm, obj = None):
return True
def has_module_perms(self,perm,obj = None):
return True
#property
def is_staff(self):
return self.is_admin
views.py
from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from rest_framework.parsers import JSONParser
from restaccount.models import RegisterUser
# Login
from restaccount.serializers import RegisterSerializers,LoginSerializer
# LoginSerializers
from django.views.decorators.csrf import csrf_exempt
from rest_framework.generics import CreateAPIView
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.permissions import (AllowAny,IsAuthenticated)
# from rest_framework.generics import CreateAPIView
class RegisterView(CreateAPIView):
permission_classes = (AllowAny,)
serializer_class = RegisterSerializers
queryset = RegisterUser.objects.all()
class LoginView(TokenObtainPairView):
serializer_class = LoginSerializer
serializers.py
from rest_framework.serializers import (ModelSerializer,ValidationError)
from restaccount.models import RegisterUser
# Login
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework import serializers
class RegisterSerializers(ModelSerializer):
class Meta:
model = RegisterUser
fields =['id',
'first_name',
'last_name',
'email',
'password',
'phone_number',
'nickname',
'birthday',
]
def create(self,validated_data):
first_name = validated_data['first_name']
last_name = validated_data['last_name']
email = validated_data['email']
password = validated_data['password']
phone_number = validated_data['phone_number']
nickname = validated_data['nickname']
birthday = validated_data['birthday']
user_obj = RegisterUser(
first_name = first_name,
last_name = last_name,
email = email,
password = password,
phone_number = phone_number,
nickname = nickname,
birthday = birthday,
)
user_obj.save()
return user_obj
def update(self, instance,validated_data):
instance.first_name = validated_data.get('first_name',instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.email = validated_data.get('email', instance.email)
instance.password = validated_data.get('password', instance.password)
instance.phone_number = validated_data.get('phone_number', instance.phone_number)
instance.nickname = validated_data.get('nickname', instance.nicknames)
instance.birthday = validated_data.get('birthday',instance.birthday)
instance.save()
return instance
def validate(self,data):
return data
def validate_phone_number(self,value):
phone_number = value
user_qs = RegisterUser.objects.filter(phone_number = phone_number)
if user_qs.exists():
raise ValidationError("This phone number is registered")
return value
class LoginSerializer(TokenObtainPairSerializer):
#classmethod
def get_token(cls,user):
token = super().get_token(user)
token['phone_number'] = user.phone_number
token['password'] = user.password
return token
def validate(self,attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
data['refresh'] = str(refresh)
data['access'] = str(refresh.access_token)
data['phone_number'] = self.user.phone_number
return data

Turns out that the password field in the model have to be hashed such that
user.set_password(password). This is also the same case, if you want to create a user from the API endpoint. You have to store the hashed password in your database.
However, I don't know why this is the behaviour.

Related

Upon email verification endpoint I'm getting an Invalid token error while trying to activate a user with tokens sent to the mail?

from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser, BaseUserManager, PermissionsMixin)
from rest_framework_simplejwt.tokens import RefreshToken
class UserManager(BaseUserManager):
def create_user(self,username,email, password=None ):
if username is None:
raise TypeError("Users should have a username")
if email is None:
raise TypeError("Users should have an Email")
user =self.model(username=username, email=self.normalize_email(email))
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password=None):
if password is None:
raise TypeError("Password should not be none")
user = self.create_user(username, email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=100, unique=True, db_index=True)
email = models.EmailField(max_length=100, unique=True, db_index=True)
is_verified = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
objects = UserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
"refresh":str(refresh),
"access": str(refresh.access_token)
}
Below is the serializers.py file
from .models import User
from rest_framework import serializers
from django.contrib import auth
from rest_framework.exceptions import AuthenticationFailed
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(max_length=50, min_length=6, write_only =True)
class Meta:
model = User
fields = ["email", "username", "password"]
def validate(self, attrs):
email = attrs.get("email", '')
username = attrs.get("username", '')
if not username.isalnum():
raise serializers.ValidationError("The username should contain only alphanumeric characters")
return attrs
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class EmailVerificationSerializer(serializers.ModelSerializer):
token = serializers.CharField(max_length=555)
class Meta:
model = User
fields = ["token"]
class LoginSerializer(serializers.ModelSerializer):
email = serializers.EmailField(max_length=255,min_length=3)
password = serializers.CharField(max_length=68, min_length=6, write_only=True)
username = serializers.CharField(max_length=255,min_length=3, read_only=True)
tokens = serializers.CharField(max_length=68, min_length=6,read_only=True)
class Meta:
model = User
fields = ["email", "password","username","tokens"]
def validate(self,attrs):
email = attrs.get("email", "")
password = attrs.get("password", "")
user = auth.authenticate(email=email, password=password)
if not user:
raise AuthenticationFailed("Invalid Credentials, try again")
if not user.is_active:
raise AuthenticationFailed("Account disabled, contact admin")
if not user.is_verified:
raise AuthenticationFailed("Email is not verified")
return super().validate(attrs,{
"email":user.email,
"username": user.username,
"tokens":user.tokens
})
Below is the views.py file
**from django.shortcuts import render
from rest_framework import generics, status, views
from .serializers import EmailVerificationSerializer, RegisterSerializer, LoginSerializer
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import RefreshToken, AccessToken
from .models import User
from .utils import Util
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse
from django.conf import settings
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import jwt**
# Create your views here.
class RegisterView(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request):
user = request.data
serializer = self.serializer_class(data=user)
serializer.is_valid(raise_exception=True)
serializer.save()
user_data= serializer.data
user = User.objects.get(email=user_data["email"])
token = RefreshToken.for_user(user).access_token
current_site = get_current_site(request).domain
relativeLink = reverse("email-verify")
absurl= "http://" + current_site + relativeLink + "?token="+ str(token)
email_body ="Hi "+ user.username + " Use link below to verify your email \n" + absurl
data = {"email_body":email_body,"to_email":user.email, "email_subject":"Verify your email"}
Util.send_email(data)
return Response(user_data, status=status.HTTP_201_CREATED)
class VerifyEmail(views.APIView):
serializer_class = EmailVerificationSerializer
token_param_config = openapi.Parameter(
"token", in_=openapi.IN_QUERY, description="Description",type=openapi.TYPE_STRING)
#swagger_auto_schema(manual_parameters=[token_param_config])
def get(self,request):
token = request.GET.get("token")
try:
payload = jwt.decode(token, settings.SECRET_KEY)
user = User.objects.get(id=payload["user_id"])
if not user.is_verified:
user.is_verified = True
user.save()
return Response({"email":"Successfully activated"}, status=status.HTTP_200_OK)
except jwt.ExpiredSignatureError as identifier:
return Response({"error": "Activation Link Expired"}, status=status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as identifier:
return Response({"error": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST)
class LoginAPIView(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Below is the utils.py for sending a mail
from django.core.mail import EmailMessage
class Util:
#staticmethod #We'll use the class method without instantiating it
def send_email(data):
email =EmailMessage(
subject=data["email_subject"], body=data["email_body"], to=[data["to_email"]])
email.send()
Below is the urls.py
from django.urls import path
from .views import RegisterView, VerifyEmail, LoginAPIView
urlpatterns = [
path("register/", RegisterView.as_view(), name="register"),
path("email-verify/", VerifyEmail.as_view(), name="email-verify"),
path("login/", LoginAPIView.as_view(), name="login")
]
Below is the verification mail sent
A verification mail sent
Below are the error gotten while trying to verify the token
A screenshot image description
at VerifyEmailView class the payload needs the algorithm with which you decode your token.`class VerifyEmail(views.APIView):
serializer_class = EmailVerificationSerializer
token_param_config = openapi.Parameter(
"token", in_=openapi.IN_QUERY, description="Description",type=openapi.TYPE_STRING)
#swagger_auto_schema(manual_parameters=[token_param_config])
def get(self,request):
token = request.GET.get("token")
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms='HS256')
user = User.objects.get(id=payload["user_id"])
if not user.is_verified:
user.is_verified = True
user.save()
return Response({"email":"Successfully activated"}, status=status.HTTP_200_OK)
except jwt.ExpiredSignatureError as identifier:
return Response({"error": "Activation Link Expired"}, status=status.HTTP_400_BAD_REQUEST)
except jwt.exceptions.DecodeError as identifier:
return Response({"error": "Invalid token"}, status=status.HTTP_400_BAD_REQUEST)`

I have a question about django rest auth customization

I'm trying to solve some of the things that don't fit me in the current django rest auth.
First of all, I would like to make it possible to sign up as a member only once I enter the password without using password2 in the rest auth.
And when I sign up as a member, the following error occurs when I insert the duplicate email.
UNIQUE constraint failed: api_user.email
How can I solve these problems? Here is my code.
models.py
from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser, PermissionsMixin
from django.utils.translation import ugettext_lazy as _
class UserManager(BaseUserManager):
use_in_migrations = True
def create_user(self, email, profile, userName, password):
user = self.model(
email=self.normalize_email(email),
userName=userName,
profile=profile,
)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, userName, profile):
user = self.create_user(
email=self.normalize_email(email),
password=password,
userName=userName,
profile=profile,
)
user.is_staff = True
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(_('email address'), unique=True)
userName = models.CharField(max_length=10)
profile = models.ImageField(default='default_image.jpeg')
is_staff = models.BooleanField(_('staff status'), default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['userName', 'profile']
serializers.py
from .models import User
from rest_framework import serializers
from rest_auth.registration.serializers import RegisterSerializer
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer, TokenRefreshSerializer
from rest_framework_simplejwt.tokens import RefreshToken
from allauth.account import app_settings as allauth_settings
from allauth.utils import email_address_exists
from allauth.account.adapter import get_adapter
from allauth.account.utils import setup_user_email
from django.utils.translation import ugettext_lazy as _
from datetime import datetime, timedelta
class customRegisterSerializer(RegisterSerializer):
username = None
userName = serializers.CharField(required=True)
profile = serializers.ImageField(use_url=True)
def validate_email(self, email):
email = get_adapter().clean_email(email)
if allauth_settings.UNIQUE_EMAIL:
if email and email_address_exists(email):
raise serializers.ValidationError(
_("A user is already registered with this e-mail address."))
return email
def validate_password(self, password):
return get_adapter().clean_password(password)
def get_cleaned_data(self):
return {
'email': self.validated_data.get('email', ''),
'password': self.validated_data.get('password', ''),
'userName': self.validated_data.get('userName', ''),
'profile': self.validated_data.get('profile', ''),
}
def save(self, request, **kwargs) :
adapter = get_adapter()
user = adapter.new_user(request)
user.save()
return user
class customTokenObtainPairSerializer(TokenObtainPairSerializer):
def validate(self, attrs):
data = super().validate(attrs)
refresh = self.get_token(self.user)
del(data['refresh'])
del(data['access'])
data['token_type'] = 'bearer'
data['access_token'] = str(refresh.access_token)
data['expires_at'] = str(datetime.now() + timedelta(hours=6))
data['refresh_token'] = str(refresh)
data['refresh_token_expires_at'] = str(datetime.now() + timedelta(days=30))
return data
class customTokenRefreshSerializer (TokenRefreshSerializer) :
def validate(self, attrs):
data = super().validate(attrs)
refresh = RefreshToken(attrs['refresh'])
del(data['refresh'])
data['token_type'] = 'bearer'
data['access_token'] = str(refresh.access_token)
data['expires_at'] = str(datetime.now() + timedelta(hours=6))
data['refresh_token'] = str(refresh)
data['refresh_token_expires_at'] = str(datetime.now() + timedelta(days=30))
return data
thanks in advance

Integrity Error: NOT NULL constraint failed: users_profile.user_id

I want to implement update User Profile,in django rest framework.
I am getting the above mentioned error, no matter what I try and change in my code.
Below is the the code for my user serializers, user model and api views.
users/api/serializers.py:
from rest_framework import serializers
from ..models import User,Profile
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username','first_name','last_name','phone','id')
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Profile
fields = ('user', 'bio', 'image')
def update(self,instance,validated_data):
user_data = validated_data.pop('user',{})
user = instance.user
instance.bio = validated_data.get('bio',instance.bio)
instance.image = validated_data.get('image',instance.image)
instance.save()
return instance
Is there anything wrong in my serializer, cause I tried hardcoding and saving a particular user profile also by using for ex: instance.user.id = 21 and then saving it, but i get the same error
Is there anything wrong in my serializer, cause I tried hardcoding and saving a particular user profile also by using for ex: instance.user.id = 21 and then saving it, but i get the same error
users/models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from django.conf import settings
import os
import random
import string
class MyAccountManager(BaseUserManager):
def create_user(self,phone,username,first_name,last_name):
if not phone:
raise ValueError("Users must have a valid phone number")
if not username:
raise ValueError("Users must have a valid username")
if not first_name:
raise ValueError("Users must have a valid First Name")
if not last_name:
raise ValueError("Users must have a valid last name")
user = self.model(
phone=phone,
username=username,
first_name=first_name,
last_name=last_name
)
user.save(using=self._db)
return user
def create_superuser(self,username,phone,first_name,last_name,password = None):
user = self.create_user(
username=username,
phone=phone,
first_name=first_name,
last_name=last_name,
)
user.set_password(password)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
class User(AbstractBaseUser):
phone = models.CharField(unique=True,max_length=20)
username = models.CharField(max_length=50,unique=True)
first_name = models.CharField(max_length=40)
last_name = models.CharField(max_length=30, blank=True)
date_joined = models.DateTimeField(verbose_name='date_joined', auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login', auto_now_add=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
otp = models.CharField(max_length=10,default='')
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = ['username','first_name','last_name']
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self,perm,obj = None):
return self.is_admin
def has_module_perms(self,app_label):
return True
class Profile(models.Model):
user = models.OneToOneField(User,on_delete = models.CASCADE)
bio = models.CharField(max_length=140)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}'
users/api/views.py
from rest_framework import status
from rest_framework.response import Response
from rest_framework import viewsets
from rest_framework.views import APIView
from .serializers import UserSerializer,UserProfileSerializer
from ..models import User,Profile
from django_filters.rest_framework import DjangoFilterBackend
class ProfileViewset(viewsets.ModelViewSet):
model = Profile
serializer_class = UserProfileSerializer
queryset = Profile.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ['user']
Please add null=True if you want to insert null value.This is my suggestion
class Profile(models.Model):
user = models.OneToOneField(User,null=True,on_delete = models.CASCADE)
bio = models.CharField(max_length=140)
image = models.ImageField(default='default.jpg',upload_to='profile_pics')
def __str__(self):
return f'{self.user.username}'

Django drf simple-jwt authentication"detail": "No active account found with the given credentials"

I am implementing user authentication with django-rest_framework_simple-jwt with custom user,
My models.py:
class UserManager(BaseUserManager):
def create_user(self, email, username, password, alias=None):
user = self.model(
email = self.normalize_email(email),
username = username,)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, username, password):
self.create_user(email, username, password)
user.is_staff()
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(null=False, unique=True)
username = models.CharField(max_length=25, unique=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username",]
So I am implementing restframework simple-jwt authentication,my settings .py is as follows as:
REST_FRAMEWORK={
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
]}
my urls.py:
urlpatterns = [
url(r'^api/token/$', TokenObtainPairView.as_view(), name='token_obtain_pair'),
url(r'^api/token/refresh/$', TokenRefreshView.as_view(), name='token_refresh'),]
on login process, it returns error that "detail": "No active account found with the given credentials" all my users were active. I have no clue to sort this out, I need help.Thanks in advance.
Ensure your password is being hashed before it is stored in your db. I ran into the same problem and discovered my passwords were being stored in plain text. Adding the following to my UserSerializer solved the issue
from django.contrib.auth.hashers import make_password
def validate_password(self, value: str) -> str:
"""
Hash value passed by user.
:param value: password of a user
:return: a hashed version of the password
"""
return make_password(value)
Either you did not create a superuser for your Django application or you are provided the wrong credentials for authentication
Did you remember to set in settings:
AUTH_USER_MODEL = 'your_app_name.User'
Also make sure, is_active = True for the user object that you are saving in your serializer, because
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['fullname', 'username', 'email', 'password']
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
# Adding the below line made it work for me.
instance.is_active = True
if password is not None:
# Set password does the hash, so you don't need to call make_password
instance.set_password(password)
instance.save()
return instance
Note ( As per docs )
The login_required decorator does NOT check the is_active flag on a user, but the default AUTHENTICATION_BACKENDS reject inactive users.
It seems my error was being caused by a write_only parameter on my password field
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password']
Removed it:
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(
max_length=68, min_length=6)
class Meta:
model = User
fields = ['email', 'username', 'password']
and then it was all sunshine and rainbows after that :-)
try this
from django.contrib.auth.hashers import make_password
class UserManager(BaseUserManager):
def create_user(self, email, username, password, alias=None):
user = self.model(
email = self.normalize_email(email),
username = username,)
user.set_password(make_password(password))
user.save()
return user
def create_superuser(self, email, username, password):
self.create_user(email, username, password)
user.is_staff()
user.is_superuser = True
user.save()
return user
Downgraded manually from PyJWT==2.0.0 to PyJWT==1.7.1 and solved our problem
pip install PyJWT==1.7.1
We are using djangorestframework==3.12.1 and djangorestframework-simplejwt==4.4.0 on our requirements.txt and that gave us automatically the 2.0.0 version dependency.
In my opinion, there is a problem where an email address and username is provided for the serializer, but an email is expected as a username for authentication.
I had the same error too. I also made some kind of custom user and tried to login to get a couple of json web tokens. But I only used email, not username. So what I did in the end and it works for me. Perhaps this example explains something in the place where authentication is done ...
Model and manager like this:
from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import (
AbstractBaseUser,
BaseUserManager
)
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ObjectDoesNotExist
from rest_framework_simplejwt.tokens import RefreshToken
class CustomUserManager(BaseUserManager):
def get_or_create(self, email=None, **kwargs):
allowed_kwargs = ['first_name', 'last_name', 'img', 'about']
if email is not None:
try:
user_obj = super(CustomUserManager, self).get(email=email)
if kwargs:
for k, v in kwargs.items():
setattr(user_obj, k, v)
user_obj.save()
except ObjectDoesNotExist:
email = self.normalize_email(email)
user_obj = self.model(email=email)
password = kwargs.pop('password', None)
if password is not None:
user_obj.set_password(password)
if kwargs:
for k, v in kwargs.items():
if k in allowed_kwargs:
setattr(user_obj, k, v)
user_obj.save()
else:
return False
return user_obj
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), null=True, unique=True)
first_name = models.CharField(max_length=150, null=True, blank=True)
last_name = models.CharField(max_length=150, null=True, blank=True)
img = models.URLField(null=True, blank=True)
about = models.TextField(_('about'), max_length=500, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
def __str__(self):
return f'<CustomUser(id={self.id} - email={self.email})>'
class Meta:
ordering = ['-created_at']
#property
def full_name(self):
if hasattr(self, 'first_name') and hasattr(self, 'last_name'):
return f'{self.first_name} {self.last_name}'
return 'No fullname'
#property
def jwt_tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token),
}
Customizing token serializer:
from django.contrib.auth import authenticate
from django.contrib.auth.models import update_last_login
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import serializers
class CustomTokenSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
email = serializers.EmailField(required=True)
password = serializers.CharField(min_length=8, write_only=True)
def validate(self, email, password):
try:
self.user = CustomUser.objects.get(email=email)
except ObjectDoesNotExist as e:
message = {'error': f'User with email={email} does not exist.'}
return message
check_auth = authenticate(username=email, password=password)
if check_auth is None:
message = {'error':
'The user exists, but the password is incorrect.'}
return message
data = self.user.jwt_tokens
update_last_login(None, self.user)
return data
Urls:
urlpatterns += [
path('login/token/', views.LoginTokenView.as_view(), name='login-token')
]
I faced a similar issue. Turns out that I had not included the password field among the fields in the Writer serializer.
Before I had code like this;
class UserWriterSerializer(serializers.ModelSerializer):
class Meta:
model = AppUser
fields = [
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'telephone',
'userType',
'gender',
'registration_date'
]
Then I added the password field to have this;
class UserWriterSerializer(serializers.ModelSerializer):
class Meta:
model = AppUser
fields = [
'id',
'username',
'password',
'first_name',
'last_name',
'email',
'is_active',
'telephone',
'userType',
'gender',
'registration_date'
]
So in summary, some different value was being saved in the database which was not the password I added. Thus having that error, because the password you place as an input is not matching with what is in the database. Make sure that the serializer is correct

How to add a Boolean choice/ radio button in a registration form for custom user in django

I am new to django, trying to create a custom registration form. I wanted to add a radio button in the user registration to know whether the user is giving a facebook id or linkedin id. Please help me in completing this.
in my models.py
from django.db import models
from django.contrib.auth.models import User, BaseUserManager, AbstractUser
class Registration(models.Model):
u = models.BooleanField(default=False)
model = User
def __unicode__(self):
return self.u
class CustomUserManager(BaseUserManager):
def create_user(self, u ):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
u = models.BooleanField('u:')
model = User
user = self.model(
u = u
)
user.save(using=self._db)
return user
def create_superuser(self, u):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(
u,
)
user.is_admin = True
user.save(using=self._db)
return user
class CustomUser(AbstractUser):
objects = CustomUserManager()
pass
class LinkedInUser(CustomUser):
linkedin_id = models.CharField(max_length=30, unique=True)
class Meta:
verbose_name = 'LinkedIn User'
class FacebookUser(CustomUser):
facebook_id = models.CharField(max_length=30, unique=True)
class Meta:
verbose_name = 'Facebook User
in my forms.py
from django import forms
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from .models import CustomUser, LinkedInUser, FacebookUser
import re
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth import get_user_model
class RegistrationForm(forms.ModelForm):
username = forms.RegexField(regex=r'^\w+$', widget=forms.TextInput(attrs=dict(required=True, max_length=30)), label=_("username"), error_messages={ 'invalid': _("This value must contain only letters, numbers and underscores.") })
email = forms.EmailField(widget=forms.TextInput(attrs=dict(required=True, max_length=30)), label=_("Email address"))
password1 = forms.CharField(widget=forms.PasswordInput(attrs=dict(required=True, max_length=30, render_value=False)), label=_("Password"))
password2 = forms.CharField(widget=forms.PasswordInput(attrs=dict(required=True, max_length=30, render_value=False)), label=_("Password (again)"))
CHOICES = (
('LinkedInUser', 'LinkedInUser'),
('FacebookUser', 'FacebookUser'),
)
u = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect())
# _ = forms.TypedChoiceField(
# coerce=lambda x: x == 'True',
# choices=((LinkedInUser, 'LinkedInUser'), (FacebookUser, 'FacebookUser')),
# widget=forms.RadioSelect
# )
class Meta :
User = get_user_model()
def clean_name(self):
try:
user = User.objects.get(username__iexact=self.cleaned_data['username'])
except User.DoesNotExist:
return self.cleaned_data['username']
raise forms.ValidationError(_("The username already exists. Please try another one."))
def clean(self):
if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
if self.cleaned_data['password1'] != self.cleaned_data['password2']:
raise forms.ValidationError(_("The two password fields did not match."))
return self.cleaned_data
class CustomUserCreationForm(UserCreationForm):
def clean_username(self):
# Since User.username is unique, this check is redundant,
# but it sets a nicer error message than the ORM. See #13147.
username = self.cleaned_data["username"]
try:
CustomUser._default_manager.get(username=username)
except CustomUser.DoesNotExist:
return username
raise forms.ValidationError(self.error_messages['duplicate_username'])
class LinkedInUserCreationForm(UserCreationForm):
linkedin_id = forms.CharField(label="LinkedIn Id", max_length=30, required=True,
help_text="Required. 30 characters or fewer.")
class Meta:
User = get_user_model()
model = LinkedInUser
fields = [
'linkedin_id'
]
class FacebookUserCreationForm(UserCreationForm):
facebook_id = forms.CharField(label="Facebook Id", max_length=30, required=True,
help_text="Required. 30 characters or fewer.")
class Meta:
User = get_user_model()
model = FacebookUser
fields = [
'facebook_id'
]