Django - Authenticate returns None despite AUTHENTICATION_BACKENDS - python

I try to make a login using a LoginView class. I just can't login. It always says that my password is wrong but it isn't (I checked it with check_password()). I already set AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend'] in my settings.py.
Here's my clean function in my custom AuthenticationForm:
def clean(self):
cleaned_data = self.cleaned_data
username = cleaned_data.get("username")
password = cleaned_data.get("password")
user = authenticate(username=username, password=password)
print(user)
print(username)
print(password)
try:
us = User.objects.get(username=username)
print(us)
print(us.check_password(password)) # This returns True!!!
except ObjectDoesNotExist:
pass
if user is not None:
if not user.is_active:
raise forms.ValidationError("Dieser Account ist deaktiviert. Du kannst ihn über deine E-Mail aktivieren.")
else:
raise forms.ValidationError("Falsches Passwort")
return cleaned_data

The ModelBackend authenticate method does this:
def authenticate(self, request, username=None, password=None, **kwargs):
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.get_by_natural_key(username)
except UserModel.DoesNotExist:
# Run the default password hasher once to reduce the timing
# difference between an existing and a nonexistent user (#20760).
UserModel().set_password(password)
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
and user_can_authenticate is:
def user_can_authenticate(self, user):
"""
Reject users with is_active=False. Custom user models that don't have
that attribute are allowed.
"""
is_active = getattr(user, 'is_active', None)
return is_active or is_active is None
Does your user have is_active set to True?

Related

How to write custom Username validation using Self.clean_username for Profile Update form in Django?

I am a beginner and I'm still learning Django. I am writing my custom form validation for user profile update. My profile update form has -
username
first name
last name
profile image
First I have used default form validation. It is also good but I want to update the error message so I tried to create a custom validation function as I seen in a post in Stack Overflow. Please also check my username validation in forms.py
So what is the error now?
Now I am facing one more issues
If I click on update button without changing anything then it shows can't use this username. {username is set to unique=True in model fields}
If I don't update username and update just first name and last name. It doesn't allow this says same error. "Username is already taken" {because that username is validated and it already taken by current user"}
What exactly I want?
Instead of changing just error message now I want to write my own validation for this. I want if some click on update without changing any data no error message should be shown.
I can update each field independently. No error message should be shown if i don't update username.
My Views
#login_required()
def profile(request):
if request.method=='POST':
u_form = UserUpdateForm(request.POST,request.FILES,instance=request.user)
if u_form.is_valid():
u_form.save()
messages.success(request, f'Profile Updated Succesfully')
redirect('profile/')
else:
u_form = UserUpdateForm(instance=request.user)
notes = UserCreatedNote.objects.filter(user=request.user)
context = {'u_form': u_form,'notes':notes}
return render(request,'profile.html',context)
My models
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
# ///////////////User Manager/////////////////////
# Create your models here.
# overriding the create and superuser funciton
class MyAccountManager(BaseUserManager):
def create_user(self,email,username,password=None):
if not email:
raise ValueError("Users Must Have email Address")
if not username:
raise ValueError("Users Must Have username")
user = self.model(
email=self.normalize_email(email),
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,email,username,password):
user = self.create_user(
email = self.normalize_email(email),
username=username,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
# ////////////////////////////////////////////////////////////
def get_profile_image_filepath(self,filename):
return f'profile_images/{self.pk}/{filename}' #pk= primary key
def get_default_profile_image():
return "img/default_profile/default.png"
class KeepSafeUserModel(AbstractBaseUser):
first_name = models.CharField(verbose_name='first_name',max_length=30,default="")
last_name = models.CharField(verbose_name='last_name',max_length=30,default="")
email= models.TextField(verbose_name='email',max_length=60,unique=True,primary_key=True)
username = models.CharField(max_length=30,unique=True)
date_joined = models.DateTimeField(verbose_name="date joined",auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login',auto_now=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
profile_image = models.ImageField(max_length=225,upload_to=get_profile_image_filepath,null=True,blank=True,default=get_default_profile_image)
#password field is buil-in
objects = MyAccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
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
def get_profile_image_filename(self):
return str(self.profile_image)[str(self.profile_image).index('profile_images/{self.pk}/')]
forms.py
class UserUpdateForm(forms.ModelForm):
profile_image = forms.ImageField(required=False,error_messages ={'invalid':("Image files only")},widget=forms.FileInput)
class Meta:
model = KeepSafeUserModel
fields = ['username','first_name','last_name','profile_image']
labels ={
'username':'Username',
'first_name':'First Name',
'last_name':'Last Name',
'profile_image':'Profile Image'
}
def clean_username(self):
username = self.cleaned_data['username']
if not username.isdigit():
users = KeepSafeUserModel.objects.filter(username__iexact=username)
if users:
raise forms.ValidationError("Username has already taken by someone else")
else:
raise forms.ValidationError("Username can't contains only numbers")
return username
The problem is that if you update your KeepSafeUserModel, you will have a hit for KeepSafeUserModel.objects.filter(username__iexact=username): indeed, it will simply match with itself.
You can simply exclude the object with:
def clean_username(self):
username = self.cleaned_data['username']
if not username.isdigit():
users = KeepSafeUserModel.objects.exclude(pk=self.instance.pk).filter(
username__iexact=username
).exists()
if users:
raise forms.ValidationError"Username has already taken by someone else")
else:
raise forms.ValidationError("Username can't contains only numbers")
return username
I think you already pass the instance of user logged in to the form. So you need to make the clean_username(self) validation become like this.
def clean_username(self):
username = self.cleaned_data['username']
if not username.isdigit():
users = KeepSafeUserModel.objects.filter(username__iexact=username)
if users:
if users.username != self.instance.username:
raise forms.ValidationError("Username has already taken by someone else")
else:
raise forms.ValidationError("Username can't contains only numbers")
return username
It will validate the username given and stored is not same

KeyError at /api/login 'user'

This user keyword error is showing in my login api. I am not sure why. I am guessing user instance is not available in the login view. I am new and I dont know the reason.
This is my login view:
class LoginUserView(GenericAPIView):
permission_classes = [AllowAny]
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
data = request.data
serializer = UserLoginSerializer(data=data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data["user"]
token, created = Token.objects.get_or_create(user=user)
return response.Response({"token": token.key}, status=status.HTTP_200_OK)
This is my serializers:
class UserLoginSerializer(serializers.ModelSerializer):
email = serializers.EmailField(label='Email Address')
class Meta:
model = User
fields = [
'email', 'password',
]
extra_kwargs = {"password":
{"write_only": True}}
def validate(self, data):
# user = None
email = data.get("email", None)
password = data.get("password")
if not email:
raise serializers.ValidationError("Email is required for login")
if not password:
raise serializers.ValidationError("Password is required for login")
user = authenticate(email=email, password=password)
if not user:
raise serializers.ValidationError("This email is not valid/already exists")
return data
The serializer has no user in its validated data. Note that serializer.validated_data['user'] makes not much sense, since you never passed this to the validator.
You should add it to the data with:
def validate(self, data):
# user = None
email = data.get('email', None)
password = data.get('password')
if not email:
raise serializers.ValidationError('Email is required for login')
if not password:
raise serializers.ValidationError('Password is required for login')
user = authenticate(email=email, password=password)
if not user:
raise serializers.ValidationError('This email is not valid/already exists')
data['user'] = user
return data

auth is returned as none when trying to log in user when signing up

I am trying to solve the use case where when user signs up then the user is automatically logged in and return the token of that user so that i can that token in cookies from frontend. However, I get issue "Email already registered". when i debug my code using pdb, i found that auth = authenticate(username=email, password=password) is returning None.
How can I authenticate user during signup and pass token of that user?
Here is how i am doing
class Register(graphene.Mutation):
'''
Mutation to register a user
'''
class Arguments:
email = graphene.String(required=True)
password = graphene.String(required=True)
password_repeat = graphene.String(required=True)
success = graphene.Boolean()
errors = graphene.List(graphene.String)
email = graphene.String()
def mutate(self, info, email, password, password_repeat):
if password == password_repeat:
try:
serializer = RegistrationSerializer(data={
'email': email,
'password': password,
'is_active': False
})
if serializer.is_valid():
user = serializer.save()
auth = authenticate(username=email, password=password)
import pdb
pdb.set_trace()
# login user and pass the token
login(info.context, auth)
return Register(success=bool(user.id), email=user.email)
else:
print("error", serializer.errors)
except Exception:
errors = ["email", "Email already registered"]
return Register(success=False, errors=errors)
errors = ["password", "Passwords don't match."]
return Register(success=False, errors=errors)
class Login(graphene.Mutation):
"""
Mutation to login a user
"""
class Arguments:
email = graphene.String(required=True)
password = graphene.String(required=True)
success = graphene.Boolean()
errors = graphene.List(graphene.String)
token = graphene.String()
user = graphene.Field(UserQuery)
def mutate(self, info, email, password):
user = {'email': email, 'password': password}
serializer = JSONWebTokenSerializer(data=user)
if serializer.is_valid():
token = serializer.object['token']
user = serializer.object['user']
print('user', user)
return Login(success=True, user=user, token=token)
else:
print("serializers errors", serializer.errors)
return Login(
success=False,
token=None,
errors=['email', 'Unable to login with provided credentials.']
)
RegistrationSerializer
class RegistrationSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'is_active', 'password', )
def create(self, validated_data):
print("validated_data", validated_data)
user = User.objects.create(**validated_data)
user.set_password(validated_data['password'])
user.save()
return user
I am using graphql instead of REST API and I am using graphene-django for graphql.

Allowing both email and username login in django project

I'm creating a django project for a school, and there are three main kinds of users - parents, teachers, and students. For parents and teachers, I would like them to login using email (they are currently using email logins for a legacy system).
However, for students, I would like them to login using the conventional username approach (since young kids don't have emails). Is this possible to do in Django or is there only one User Authentication model allowed?
You can create separate AuthenticationEmailBackend just for logging by email and add it to AUTHENTICATION_BACKENDS in settings. In this way different AUTHENTICATION_BACKENDS are used as alternatives if authentication fails for previous AUTHENTICATION_BACKENDS.
app/auth.py
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
class AuthenticationEmailBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if getattr(user, 'is_active', False) and user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
settings.py
AUTHENTICATION_BACKENDS = (
"django.contrib.auth.backends.ModelBackend",
...
"app.auth.AuthenticationEmailBackend",
)
If you leave default django.contrib.auth.backends.ModelBackend in a list users can login by either username or email.
Seems request parameter is needed in authenticate method from Django 1.11:
def authenticate(self, request, username=None, password=None)
According to what is said in Django documentation.
A simple backend which allows you to login with either an email address or a username.
It should be combined with another backend for checking permissions:
settings.py:
AUTHENTICATION_BACKENDS = (
'myproject.accounts.backends.EmailOrUsernameModelBackend',
'django.contrib.auth.backends.ModelBackend' )
account/backends.py:
from django.conf import settings
from django.contrib.auth.models import User
class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None):
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'username': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
and for case-insensitive :
class EmailOrUsernameModelBackend(object):
def authenticate(self, username=None, password=None):
# user_model = get_user_model()
if '#' in username:
# kwargs = {'email': username}
field = 'email'
else:
# kwargs = {'username': username}
field = 'username'
try:
case_insensitive_username_field = '{}__iexact'.format(field)
user = User._default_manager.get(**{case_insensitive_username_field: username})
# user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
For Django 3.0:
# myapp/backends.py
from django.contrib.auth.backends import BaseBackend
from .models import MyUser
class EmailAuthenticationBackend(BaseBackend):
def authenticate(self, request, **kwargs):
email = kwargs['username'].lower() # If you made email case insensitive add lower()
password = kwargs['password']
try:
my_user = MyUser.objects.get(email=email)
except MyUser.DoesNotExist:
return None
else:
if my_user.is_active and my_user.check_password(password):
return my_user
return None
def get_user(self, user_id):
try:
return MyUser.objects.get(pk=user_id)
except MyUser.DoesNotExist:
return None
This works for Django 2.0 and probably previous versions:
# myapp/backends.py
from django.contrib.auth.backends import ModelBackend
from .models import MyUser
class EmailAuthenticationBackend(ModelBackend):
def authenticate(self, request, **kwargs):
email = kwargs['username']
password = kwargs['password']
try:
my_user = MyUser.objects.get(email=email)
except MyUser.DoesNotExist:
return None
else:
if my_user.is_active and my_user.check_password(password):
return my_user
return None
(Not sure if it is a good idea to extend the ModelBackend, you can crete your own class)
And then, for both versions:
# settings.py
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"myapp.backends.EmailAuthenticationBackend",
]
in models.py
class UserDet(models.Model):
email = models.EmailField(max_length=20)
userName = models.CharField(max_length=20)
in views.py
def user_login(request):
response_data={}
if request.session.has_key('login_id'): #If user already logedin send to dashboard else check userid and password
return render(request, '/dashboard.html')
else:
if request.method == 'POST': # If request method is post then only process request
#print('here in login')
try:
username = request.POST.get('username')
password = request.POST.get('pass')
if '#' in username: #check for email
try:
for u in UserDet.objects.filter(email=username):
#username=u['userName']
username=u.userName
except:
response_data['code']=1000
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
if not request.POST.get('rememberme', None): # check user select the remember me or not if yes then create session that expire after long time
#print('seeing it 0')
request.session.set_expiry(0)
user = authenticate(username=username, password=password) # Check user exist or not
if user: #if user exist then
if user.is_active: #check user is active or not if active then successfully loged in else send error
login(request,user)
update_last_login(None, user)
request.session['login_id'] = user.id
response_data['code']=800
response_data['status']='success'
return HttpResponse(json.dumps(response_data), content_type="application/json")
#return render(request, '/dashboard.html')
else:
response_data['code']=900 #Error for User is not active
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
#return HttpResponse("Your account was inactive.")
else: #Error or Invalid username or password
#print("Someone tried to login and failed.")
#print("They used username: {} and password: {}".format(username,password))
response_data['code']=1000
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
except:
response_data['code']=1001
response_data['status']='fail'
return HttpResponse(json.dumps(response_data), content_type="application/json")
else: #Return to index
return redirect('/', {})

Authentication is not working foer custom user model

Why the authentication is not working with custom model "Consultants".i have tried a lot but it not working
models.py
class Consultants(models.Model):
# user=models.OneToOneField(User)
consul_id=models.IntegerField(default=0,primary_key=True)
first_name=models.CharField(max_length=255,blank=True,null=True)
last_name=models.CharField(max_length=255,blank=True,null=True)
email=models.EmailField(max_length=255,blank=True,null=True)
username=models.CharField(max_length=255,blank=True,null=True)
password=models.CharField(max_length=50,blank=True,null=True)
consul_pic=models.ImageField(upload_to="/home/cp/Documents/consul_pic",blank=True,null=True)
mobile_no=models.CharField(max_length=255,blank=True,null=True)
)
last_login=models.DateTimeField(default=datetime.now,blank=True,null=True)
is_active=models.BooleanField(default=False)
def __str__(self):
return self.first_name or u''
views.py
def login_user(request):
context = RequestContext(request)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
print type(username)
try:
user = authenticate(username=username, password=password)
print 'chala'
if user.is_active:
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
return HttpResponse("welcome......you are succesfuly log in")
else:
return HttpResponse("Your account is disabled.")
except ObjectDoesNotExist:
return HttpResponse("INvalid User")
else:
return render_to_response('login.html', {}, context)
when i try to authenticate it return None.
it is the correct way which i try to login please help me in it.
that is not correct way of customizing user model
you should try like this
reference : https://docs.djangoproject.com/en/1.9/topics/auth/customizing/
from django.contrib.auth.models import (AbstractBaseUser,
PermissionsMixin,
UserManager)
class Consultants(AbstractBaseUser, PermissionsMixin):
consul_id=models.IntegerField(default=0,primary_key=True)
first_name=models.CharField(max_length=255,blank=True,null=True)
last_name=models.CharField(max_length=255,blank=True,null=True)
email=models.EmailField(max_length=255,blank=True,null=True)
username=models.CharField(max_length=255,blank=True,null=True)
password=models.CharField(max_length=50,blank=True,null=True)
consul_pic=models.ImageField(upload_to="/home/cp/Documents/consul_pic",blank=True,null=True)
mobile_no=models.CharField(max_length=255,blank=True,null=True))
last_login=models.DateTimeField(default=datetime.now,blank=True,null=True)
is_active=models.BooleanField(default=False)
objects = UserManager()
def __str__(self):
return self.first_name or u''

Categories