I am unable to authenticate custom user in django==3.1.3
Here is Custom User Manager:
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _
class CustomUserManager(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 a 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 empty.'))
user = self.create_user(username, email, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
Here's the CustomUser model:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from .managers import CustomUserManager
class CustomUser(AbstractBaseUser):
username = models.CharField(max_length=255, unique=True, db_index=True)
email = models.EmailField(max_length=255, 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 = CustomUserManager()
def __str__(self):
return self.email
I have added AUTH_USER_MODEL = 'authentication.CustomUser' in settings.py
(authentication is the app name)
In the shell, if I run these, I get authenticated_user as None:
user = CustomUser.objects.create(email='tejas#gmail.com', username='tejas12', password='tejas12')
authenticated_user = authenticate(email='tejas#gmail.com', username='tejas12', password='tejas12')
However, the User gets created successfully with given details.
Also, check_password returns False:
from django.contrib.auth.hashers import check_password
user.check_password('tejas12') # returns False
On creating a user using python manage.py createsuperuser,
authenticate returns the required user, and
check_password returns True
How should I authenticate the custom users?
In your example, you create the user as a regular Django model which doesn't hash password properly
user = CustomUser.objects.create(email='tejas#gmail.com', username='tejas12', password='tejas12')
create_user method should be used instead
>>> second_user = CustomUser.objects.create_user(email='test#example.com', username='test', password='test_passwd')
>>> second_user.check_password('test_passwd')
True
Authentication uses default backend unless you specify your own and will rely on the USERNAME_FIELD and password
>>> from django.contrib.auth import authenticate
>>> authenticate(email='test#example.com', username='test', password='test_passwd')
>>> authenticate(email='test#example.com', password='test_passwd')
<CustomUser: test#example.com>
Related
I modified the Auth User by using AbstractUser Class.
Registered it in settings. Everything else is working
I can create an instance using the User Model
BUT
The Problem comes during the serialization.
My serializer doesn't throw any error, but any time I try and use the serializer.data I get AttributeError: 'str' object has no attribute '_meta'.
User Model
class User(AbstractUser):
# Add additional fields here
email = models.EmailField(max_length=254, unique=True)
name = models.CharField(max_length=100)
username = models.CharField(max_length=100)
password = models.CharField(max_length=100)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
first_name=None
last_name=None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'username', 'password']
objects = CustomUserManager()
def __str__(self):
return self.email
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
Custom Manager
from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import gettext_lazy as _
class CustomUserManager(BaseUserManager):
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
User Serializer
from rest_framework import serializers
from django.conf import settings
User = settings.AUTH_USER_MODEL
class UserSerializer(serializers.ModelSerializer):
print("UserSerializer")
class Meta:
model = User
# fields = (['id', 'username', 'email', 'name'])
fields = '__all__'
View
#api_view(['POST'])
def createUser(request):
data = request.data
serializer = UserSerializer(data,many=False)
if serializer.is_valid():
print(type(serializer.data))
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I've stuck with the code for the last 7-8 hours. Even tried specifying the fields but I haven't been able to figure out why this is happening.
You should work with the get_user_model() function [Django-doc] to obtain a reference to the user model, the AUTH_USER_MODEL setting [Django-doc] is only a string to the name of that model:
from rest_framework import serializers
from django.contrib.auth import get_user_model
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = '__all__'
I have a problem with authenticate() method. It always returns None. I checked all my arguments, and they are not empty. In models, I have USERNAME_FIELD = 'username', in settings I have AUTH_USER_MODEL = 'account.User'. I really can't understand why it's not working.
models.py
class UserManager(BaseUserManager):
def _create(self, username, password):
if not username:
raise ValueError('Username cant be empty')
user = self.model(username=username)
user.set_password(raw_password=password)
user.save()
return user
def create_user(self, username, password):
return self._create(username=username, password=password)
class User(AbstractBaseUser):
id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='id')
email = models.EmailField()
username = models.CharField(max_length=25, unique=True)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
education = models.CharField(max_length=100, blank=True)
date_of_birth = models.DateField(blank=True, null=True)
name = models.CharField(max_length=25, blank=True)
last_name = models.CharField(max_length=25, blank=True)
objects = UserManager()
USERNAME_FIELD = 'username'
views.py
class UserLoginView(ObtainAuthToken):
serializer_class = UserLoginSerializer
serializers.py
class UserLoginSerializer(serializers.Serializer):
username = serializers.CharField(required=True)
password = serializers.CharField(required=True)
def validate_username(self, username):
if not User.objects.filter(username=username).exists():
raise serializers.ValidationError('User wasn\'t found')
print(User.objects.get(username=username).password)
return username
def validate(self, data):
# authentications
request = self.context.get('request')
username = data.get('username') # test_name
password = data.get('password') # newpassword11
if username and password:
user = authenticate(username=username, password=password, request=request)
print(user)
if not user:
raise serializers.ValidationError('Invalid password')
else:
raise serializers.ValidationError('You have to type you\'re mail and password')
data['user'] = user
return data
I fixed it by changing the model to this:
class User(AbstractBaseUser, PermissionsMixin):
.....
after send post request to url routing to UserLoginView view with username and password at the post body got Json something like this at the response:
{"token":"30e0215a5f4cc521203a633452d63995d8f1fa77"}
When used AbstractBaseUser instead of AbstractUser be careful to implement all requirements of Django user model.
Tips: Do not forget to make the DRF Authentication settings correctly.
The problem was in users field, called is_active. Django allows to login only when user is active.
P.S. Thank to everyone, who tried to help :)
i have this problem .. authenticate function in django give me none while passing username and password
here is my model
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.db import models
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
class myUserExtensionManager(BaseUserManager):
def create_user(self, username, email, TypeOfUser, password=None):
if not username:
return ValueError("user must have username")
if not email:
return ValueError("user must have an email address")
if not TypeOfUser:
return ValueError("user must have type novice or expert")
user = self.model(
username=username,
email=self.normalize_email(email),
TypeOfUser=TypeOfUser,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password, TypeOfUser):
user = self.create_user(
username=username,
email=self.normalize_email(email),
password=password,
TypeOfUser=TypeOfUser
)
user.is_superuser = True
user.is_admin = True
user.is_staff = True
user.save(using=self._db)
return user
# Create your models here.
class UserExtensionApi(AbstractBaseUser, PermissionsMixin):
username = models.CharField(max_length=20, unique=True)
email = models.EmailField(verbose_name='email', max_length=60, unique=True)
TypeOfUser = models.CharField(max_length=6)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'username' # for using for login
REQUIRED_FIELDS = ['email', 'TypeOfUser']
Manager = myUserExtensionManager()
objects = myUserExtensionManager()
def __str__(self):
return self.email
def has_perm(self, perm, obj=None): # permation
return self.is_admin
def has_module_prems(self, app_label): # they permation if they admin
return True
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
and i import the obtain_auth_token from restframework django and this is the url file
from django.contrib import admin
from django.urls import path
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
path('admin/', admin.site.urls),
path('register/', Registration_view, name="register"),
path('signIn/', obtain_auth_token, name="signIn"),
]
finally i'm sending the username and password from reactjs using axios and i'm sure that the data is received in django but the result of authenticate function is always give's me None and i don't know why
I followed a tutorial on how to allow Django authentication by using email instead of the normal username, however, they didn't mention how to register the new custom user model with the admin page! I am a real beginner to Django so I would appreciate as much detail as possible! Here is my code so far:
managers.py
from django.contrib.auth.models import BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, password=None, **kwargs):
if not email:
raise ValueError('Email field is required')
email = self.normalize_email(email)
user = self.model(email=email, **kwargs)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
return self.create_user(email, password, **extra_fields)
models.py
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.utils.translation import gettext_lazy as _
from .managers import CustomUserManager
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, null=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. ''Unselect this instead of deleting accounts.'
),
)
USERNAME_FIELD = 'email'
objects = CustomUserManager()
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
return self.email
def get_short_name(self):
return self.get_full_name()
def __str__(self):
return self.email
admin.py
from django.contrib import admin
# Register your models here.
try this code in your admin.py
We can register our models with register decorator.
from django.contrib import admin
from .models import CustomUser
#admin.register(CustomUser)
class CustomUserAdmin(admin.ModelAdmin):
pass
from .models import CustomUser
class CustomUserAdmin(admin.ModelAdmin):
list_display = ('email',...) # add fields as you want
admin.site.register(CustomUser, CustomUserAdmin)
I have a custom user model and a user manager defined as follows:
/accounts/models.py
from django.contrib.auth.models import (
AbstractBaseUser,
BaseUserManager,
PermissionsMixin
)
from django.db import models
from django.utils import timezone
class UserManager(BaseUserManager):
def create_user(self, email, first_name, last_name, username=None, password=None):
if not email:
raise ValueError("Users must have a valid email address")
if not first_name and last_name:
raise ValueError("Users must have a first and last name")
created_username = ''.join([first_name.lower(), last_name[:1].lower()])
i=2
while User.objects.filter(username=created_username).exists():
created_username = ''.join([first_name.lower(), last_name[:i].lower()])
i+=1
user = self.model(
email=self.normalize_email(email),
first_name=first_name,
last_name=last_name,
username=created_username
)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password
)
user.is_staff = True
user.is_admin = True
user.is_superuser = True
user.save()
return user
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=40, blank=True)
last_name = models.CharField(max_length=40, blank=True)
username = models.CharField(max_length=40, unique=True, blank=True, editable=False)
# display_name = models.CharField(max_length=150)
bio = models.TextField(blank=True, null=True)
avatar = models.ImageField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name','last_name']
def __str__(self):
return "{} #{}".format(self.email, self.username)
def get_short_name(self):
return self.first_name
def get_full_name(self):
return ' '.join([self.first_name, self.last_name])
This seems to work perfectly when registering a superuser from the shell. I have a form and a view set up to register regular users on my site as follows:
/accounts/forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
auth_code = 'hamburger'
def validate_authorization(value):
if value != auth_code:
raise ValidationError(
_('Must have valid authorization code in order to register.')
)
class UserCreateForm(UserCreationForm):
authorization_code = forms.CharField(max_length=10, required=True, validators=[validate_authorization])
class Meta:
model = get_user_model()
fields = ("email", "first_name", "last_name", "password1", "password2", "authorization_code")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["email"].label = "Email Address"
self.fields["first_name"].label = "First Name"
self.fields["last_name"].label = "Last Name"
self.fields["password1"].label = "Password"
self.fields["password2"].label = "Password Confirmation"
self.fields["authorization_code"].label = "Authorization Code"
/accounts/views.py
from django.shortcuts import render
from django.template import RequestContext
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.core.urlresolvers import reverse_lazy
from django.views import generic
from django.http import HttpResponseRedirect
from django.contrib.auth import get_user_model
from . import forms
class SigninView(generic.FormView):
form_class = AuthenticationForm
success_url = '/dashboard/' #reverse_lazy('index')
template_name = 'accounts/signin.html'
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(self.request, **self.get_form_kwargs())
def form_valid(self, form):
login(self.request, form.get_user())
return super().form_valid(form)
class SignoutView(generic.RedirectView):
url = '/' #reverse_lazy("home")
def get(self, request, *args, **kwargs):
logout(request)
return super().get(request, *args, **kwargs)
class RegisterView(generic.CreateView):
form_class = forms.UserCreateForm
success_url = '/'
template_name = 'accounts/register.html'
def form_valid(self, form):
self.object = form.save(commit=False)
form.instance.username = ''.join([form.instance.first_name.lower(), form.instance.last_name[:1].lower()])
i=2
while get_user_model().objects.filter(username=form.instance.username).exists():
form.instance.username = ''.join([form.instance.first_name.lower(), form.instance.last_name[:i].lower()])
i+=1
form.save()
return HttpResponseRedirect(self.get_success_url())
# return super(RegisterView, self).form_valid(form)
I am at a loss as to why my superuser cannot log into the website but my regular users can. Also you will notice I have a while statement that auto generates a username based on the entered first and last name. Initially I had this only in the UserManager however, the form was bypassing the user manager and so I had to add the same block of code to my view. So there seems to be a disconnect between users created from the form versus users created from the shell (UserManager).
The authorization_code is in place because I don't want just anybody to be able to register on my site and I didn't know a better way. I am open to better suggestions.
Additional information that may be helpful
settings.py
# Set user authentication model
AUTH_USER_MODEL = 'accounts.User'
Python 3.5, Django 1.10
Thank you in advance for any advice or insight.
Problem solved.
In
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password
)
I was forgetting to set password=password,. From looking at the password field in the database, it seems this was also resulting in (as close as I can tell) bypassing <algorithm>$<iterations>$<salt> (per the Django docs https://docs.djangoproject.com/en/1.10/topics/auth/passwords/) though the password was still being hashed in some way (not being stored in plain text) the password field for superusers was considerably shorter than the password field for normal users. Whatever it was doing, it was not storing the actual password and was giving me an invalid username/password when attempting to log in with a superuser account.
So the proper way is
def create_superuser(self, email, first_name, last_name, password):
user = self.create_user(
email,
first_name,
last_name,
password=password,
)
I still don't understand why created_username is being bypassed in the UserManager when saving a user from the AuthenticationForm but I found a workaround by adding the same while statement to the view. At least all is functional now. I'm still interested to learn if anybody has further insight into this matter.