AbstractUser in Django is not authenticating - python

Django version 3.2
I have created a AbstractUser model for storing info of Bank's Customer . I am able to register the customer with username and password . But it's not getting authenticated while login .
In admin page the password is saved as plain text , which is not expected . It should be saved in hashed form by default in Django .
Please give some directions to solve this . What I am doing wrong ?
In settings.py I have added line :
AUTH_USER_MODEL = 'banking.Customer'
models.py :
'''
This stores all customers of this bank .
'''
class Customer(AbstractUser):
#username = models.CharField(max_length=128, unique=True)
#first_name = models.CharField(max_length=128)
#last_name = models.CharField(max_length=128)
#email = models.CharField(max_length=128)
phone = models.CharField(max_length=128)
#password = models.CharField(max_length=2048)
dateJoined = models.DateTimeField(auto_now_add=True)
# completed, pending, blocked, error
verificationStatus = models.CharField(max_length=128)
#USERNAME_FIELD = 'username'
#REQUIRED_FIELDS = []
def __str__(self):
return f"{self.username}, {self.first_name} {self.last_name}, {self.email}, {self.password}"
views.py :
def register(request):
if request.method == "POST":
# get the information from form
print("POST request :" + str(request.POST))
userName = request.POST["userName"]
firstName = request.POST["firstName"]
lastName = request.POST["lastName"]
email = request.POST["email"]
phone = request.POST["phone"]
password = request.POST["password"]
# insert it in DB, keep in mind that username should be unique
try:
customer = Customer(username=userName, first_name=firstName, last_name=lastName, email=email, phone=phone, password=password, verificationStatus="verified")
customer.save()
print("Database " + str(customer))
return HttpResponseRedirect(reverse('login'))
except:
# send register page agin with error message
context = {"message": userName + " userName is already taken ."}
return render(request, "banking/register.html", context)
else:
return render(request, "banking/register.html")
def login(request):
if request.method == "POST":
# get info from login form
username = request.POST["userName"]
password = request.POST["password"]
# check if user is valid
customer = None
try:
# check if userName exist in DB
print("check user")
customer = authenticate(request, username=username, password=password)
except:
customer = None
# save customer in session
if customer is not None:
login(request, customer)
return HttpResponseRedirect(reverse('mainPage'))
else:
# return to login page with error message
context = {"message": "Invalid credentials"}
return render(request, "banking/login.html", context)
else:
return render(request, "banking/login.html")

In your register() method of views.py, you have to edit your code to be:
customer = Customer(username=userName, first_name=firstName, last_name=lastName, email=email, phone=phone, verificationStatus="verified")
customer.set_password(password)
customer.save()
While saving user, we have to set passwords using set_password() method, as it will save password using appropriate hash/encryption algorithm.

You create the customer by using the models __init__ method (the constructor):
customer = Customer(username=userName, first_name=firstName, last_name=lastName, email=email, phone=phone, password=password, verificationStatus="verified")
But this does not consider the fact that the password needs to be hashed and saves the password as plain text. This causes your user to be unable to login as the authenticate function works on the premise that the password is hashed.
You should instead use the create_user [Django docs] method of the user model's manager, UserManager, which will automatically hash the password:
customer = Customer.objects.create_user(username=userName, first_name=firstName, last_name=lastName, email=email, phone=phone, password=password, verificationStatus="verified")

When creating the custom User class in Django, password encryption and saving mechanism should be handled by the Manager class.
See the code used from the EmployeeManager class in the astikgabani/Inventory-Management repository.

Related

The #login_required decoration is not working in Django (user not authenticated?)

I am trying to set up a login page and I am trying to use the #login_required decoration. However, whenever I try and log in with valid credentials I am re-directed to the 'login' page (set to re-direct unauthenticated users). I am not sure if the problem is in the #login_required decoration or perhaps the login() function is not authenticating the user.
Here is my code for the register form:
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
confirm_password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ['first_name', 'last_name', 'username', 'email', 'password']
code for login function in views.py:
def login_user(request):
if request.method =="GET":
return render(request, "main/login.html", {})
else:
username = escape(request.POST['userfield'])
password = escape(request.POST['passfield'])
try:
user = User.objects.get(username=username)
except:
user = None
if user is None:
try:
user = User.objects.get(email=username)
except:
user = None
if user is None:
messages.info(request, "*Sorry, that username or email does not exist")
return redirect('login')
pword = user.password
if check_password(password, pword):
login(request, user)
return redirect('homepage')
else:
messages.info(request, '*Sorry, that was an incorrect password')
return redirect('login')
my model for User in models.py:
class User(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
username = models.CharField(max_length=100)
email = models.EmailField(unique=True)
password = models.CharField(max_length=100)
admin = models.BooleanField(default=False)
last_login = models.DateTimeField(null=True, blank=True)
and my function to reach the 'homepage' after login:
#login_required(redirect_field_name='login')
def homepage(request):
return render(request, "main/homepage.html", {})
When you make custom user model, so you should always use AbstractBaseUser.
Note: It's also not a good practice to name same your models, django already has User model in the django.contrib.auth, so change its name.
So, you haven't specified the custom user model, so you should not able to authenticate, as by default authentication model is User which is at django.contrib.auth. So, with the current code when you make superuser through python manage.py createsuperuser and then you authenticate, so it will work.
You should use #login_required(login_url='login') instead of #login_required(redirect_field_name='login').
You need to correctly authenticate the user before logging in.
from django.contrib.auth import authenticate, login
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
More information in the documentation

Django: Integrity error when signing up to create a new user with a custom form

I have made custom forms for log in and registration in Django using HTML/CSS and not Django's form.as_p. I have the following code in views.py:
def login_user(request):
logout(request)
if request.POST:
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('/mainpage/')
else:
login_message = "Your username or password is incorrect."
return render(request, 'index.html', {'login_message': login_message})
return render(request, 'index.html')
def sign_up(request):
if request.POST:
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
password_confirm = request.POST['password-confirm']
if(valid_form(username, email, password, password_confirm)):
#create the new user
user = CustomUser(name=username, email=email, password=password)
user.save()
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/mainpage/')
else:
message = "There was a problem."
return render(request, 'index.html', {'message': message})
return render(request, 'index.html')
I have the following model for CustomUser in models.py:
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200, null=True)
email = models.EmailField(max_length=70, null=True)
password = models.CharField(max_length=50, null=True)
My code is working for the sign up and I can create a new user after inputting the username, email and password. However, when I try to sign up again and create another user I am getting the following error:
Exception Type: IntegrityError
Exception Value: UNIQUE constraint failed: Reviews_customuser.username
I am not sure why I am getting this error or how to resolve it. Any insights are appreciated.
You are extending your customuser class with 'AbstractUser' class. In this scenario, you can add columns to the auth_user table in the database.
If you want to create all the new columns for your 'auth_user' table. you can extends your customuser class with 'AbstractBaseUser' class.
"Exception Value: UNIQUE constraint failed: Reviews_customuser.username". You are getting this error because you trying to create the same user again

Django: Username is empty when a new user is created when signing in

I have made custom forms for log in and registration in Django using HTML/CSS and not Django's form.as_p. I have the following code in views.py:
def login_user(request):
logout(request)
if request.POST:
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect('/mainpage/')
else:
login_message = "Your username or password is incorrect."
return render(request, 'index.html', {'login_message': login_message})
return render(request, 'index.html')
def sign_up(request):
if request.POST:
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
password_confirm = request.POST['password-confirm']
if(valid_form(username, email, password, password_confirm)):
#create the new user
user = CustomUser(name=username, email=email, password=password)
user.save()
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/mainpage/')
else:
message = "There was a problem."
return render(request, 'index.html', {'message': message})
return render(request, 'index.html')
I have the following model for CustomUser in models.py:
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200, null=True)
email = models.EmailField(max_length=70, null=True)
password = models.CharField(max_length=50, null=True)
My code is working for the sign up and I can create a new user after inputting the username, email and password. When I check the users in the user list on the Django admin site, for the new user I created (ruby), only their email is stored and not their username. I believe this is the reason I am also having trouble logging in with this new user.
However I am not sure why the username isn't being stored for the new user I created. Any insights are appreciated.
Probably the issue is here:
user = CustomUser(name=username, email=email, password=password) # <-- Here
user.save()
You are not storing the username here. I think its better to do it either:
user = CustomUser(name=username, email=email, username=username)
user.set_password(password) # otherwise the password will be stored in plain text
user.save()
Or you can use create_user manager method to create Users.
According to django doc https://docs.djangoproject.com/en/1.8/_modules/django/contrib/auth/models/, AbstractUser has username field which is required and used for authentication:
username = models.CharField(_('username'), max_length=30, unique=True,
help_text=_('Required. 30 characters or fewer. Letters, digits and '
'#/./+/-/_ only.'),
validators=[
validators.RegexValidator(r'^[\w.#+-]+$',
_('Enter a valid username. '
'This value may contain only letters, numbers '
'and #/./+/-/_ characters.'), 'invalid'),
],
error_messages={
'unique': _("A user with that username already exists."),
})
In your case, you have a name field which is an additional field in the model, but in the views, you are passing username to name, while the required username field is not filled up.
Try to remove 'name' field in the model. Pass username to username
Since your 'CustomUser' class extends AbstractUser (which provides the full implementation of the default User as an abstract model), you should use the same signature (username, instead of name) as follows:
#create the new user
user = CustomUser(username=username, email=email, password=password)

Authenticating the username and password returns user as none during logn

While i am authenticating the login form using authenticate function i am getting user as none eventhough getting the username and password.
settings.py:
---------
AUTHENTICATION_BACKENDS = ("django.contrib.auth.backends.ModelBackend",)
forms.py:
----------
class UserRegistrationForm(forms.Form):
fname = forms.CharField(required=True,label='FirstName',max_length=32)
lname = forms.CharField(required=True,label='LastName',max_length=32)
username = forms.CharField(required = True,label = 'Username',max_length = 32)
password = forms.CharField(required = True,label = 'Password',max_length = 32,min_length=8)
class login_form(forms.Form):
username = forms.CharField()
password1 = forms.CharField(widget=forms.PasswordInput)
views.py:
--------
def signup(request):
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
userObj = form.cleaned_data
username = userObj['username']
password = userObj['password']
fname = userObj['fname']
lname = userObj['lname']
print (username,password,fname,lname)
if(len(password)<8):
messages.error(request,"This password length should be minimum 8 characters")
# raise ValidationError("This password length should be minimum 8 characters ")
if not (User.objects.filter(username=username).exists()):
p = Event(fname=fname, lname=lname, username=username, password=password)
p.save()
# return HttpResponseRedirect('Login.html')
return redirect('/Login/')
else:
raise forms.ValidationError('Looks like a username with that username or password already exists')
else:
form = UserRegistrationForm()
return render(request, 'signup.html', {'form':form})
def Login(request):
form = login_form(request.POST or None)
if form.is_valid():
username = form.cleaned_data.get("username")
password = form.cleaned_data.get("password1")
print (username,password)
user = authenticate(username=username, password=password)
print('user is', user)
models.py
:--------
class MyUserManager(BaseUserManager):
def create_user(self, fname,lname,username, password):
"""
Creates and saves a User with the given username, date of
birth and password.
"""
if not username:
raise ValueError('Users must have an username')
user = self.model(username=username,fname=fname,lname=lname)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, fname,lname,username, password,email=None):
"""
Creates and saves a superuser with the given username and password.
"""
user = self.create_user(
fname=fname,
lname=lname,
username=username,
password=password,
)
user.is_admin = True
user.is_superuser = True
user.save(using=self._db)
return user
class Event(AbstractBaseUser):
fname = models.CharField('fname', max_length=120)
lname = models.CharField('lname',max_length=120)
username = models.CharField('username',max_length = 60,unique=True)
password = models.CharField('password',max_length=120,default='pavi#2789')
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['fname','lname']
objects = MyUserManager()
def __unicode__(self):
return self.username
class Meta:
# managed = False
db_table = "user"
# fields = ('username', 'fname', 'lname', 'password', 'password2')
In database side the login credentials are saved.I dont know what is going wrong here.
Here Event is nothing but the model which i have created .
I have updated my models.py with the AbstractBaseUser, BaseUserManager and login using the superuser credentials it is working but when i am creating the user with the singup form the login is not working and throwing me the error as Manager isn't available; 'auth.User' has been swapped for 'Provisioning.Event'
This isn't right at all. You can't just declare a random model and expect it to work for authentication. You need to subclass AbstractBaseUser and add your fields, declare your model in the AUTH_USER_MODEL setting, and set the password appropriately on save.
from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
class Event(AbstractBaseUser):
...
And in settings.py:
AUTH_USER_MODEL = 'myapp.Event'
Now, when you create the user in the view, you need to use set_password to hash the password:
p = Event(fname=fname, lname=lname, username=username)
p.set_password(password)
p.save()
Also, note that the checking of existing usernames should be taken care of in the view - which would happen automatically if you used a ModelForm. Even better, use the built-in UserCreationForm from django.contrib.auth.forms. (But whatever you do, note that it makes no sense at all to filter on User, since you aren't using that model at all.)
The problem is not with the call to authenticate, but probably with how you are implementing the custom user model.
Using a custom user model is totally fine, and is very useful, but if you want to keep things easy for yourself, let Django handle the password part.
There's a great guide on how to write your own user model and still have it play nicely with built-in Django functionality, like authentication: https://docs.djangoproject.com/en/2.1/topics/auth/customizing/#specifying-a-custom-user-model
The reason for this is because Django hashes passwords for storage in the database for security. There's a lot of nuance to how Django handles passwords. It's quite fascinating if you're interested: https://docs.djangoproject.com/en/2.1/topics/auth/passwords/#how-django-stores-passwords

Django Python How to Compare Encrypt User's Password

I am working a project which is like CMS (Content Management System) for a website. I am developing this system with django python. But I am new to django python.
I have my own User model (not django user model) that contains some fields like username, email, password etc. and I create new user from my own admin panel.
How can I compare encrypted password with user's password that post on login page.
For example first time I create user, the password for 123 saved on db like pbkdf2_sha24123$000asd$... After that I am trying to login with password 123 but I get error that the passwords are not equals.
from django.contrib.auth.hashers import make_password
from account.models import myUsers
password = make_password(request.POST.get('password'))
email = request.POST.get('email')
if myUsers.password == password and myUsers.email == email:
#make login and redirect to panel
else:
#show error message
my own model like;
class myUsers(models.Model):
username = models.CharField(max_length=25, verbose_name='username', unique=True)
email = models.CharField(max_length=225, verbose_name='email', unique=True)
password = models.CharField(max_length=225, verbose_name='password')
created_at = models.DateTimeField(auto_now_add=True, verbose_name='created date')
secret_question = models.CharField(max_length=225, verbose_name='secret question')
secret_answer = models.CharField(max_length=225, verbose_name='secret answer')
last_login = models.DateTimeField(verbose_name='last login')
secret_guid_key = models.CharField(max_length=15, verbose_name='recover key', unique=True, editable=False, default=uuid.uuid4().hex[:15])
user_role = models.CharField(max_length=6, verbose_name='member role')
A User Object has a method called check_password() that hashes and checks your plain text password against the hashed password stored in the DB.
https://docs.djangoproject.com/en/2.2/ref/contrib/auth/#django.contrib.auth.models.User.check_password
Example Usage:
from account.models import myUsers
password = request.POST.get('password')
email = request.POST.get('email')
user = myUsers.objects.get(email=email)
if user.check_password(password):
# Success Code
else:
# Error Code
i think you should try django authenticate function.
user = authenticate(username=username, password=password)
You shuoldn't compare passwords:
if myUsers.password == password ..:
but rather the hash of the password:
if myUsers.password == myPasswordHashFunction(password) ..:
how to write myPasswordHashFunction is something you should know in detail, or you're better off using django's authenticate function.
If you're not a security expert, then please (please!) don't invent your own way to authenticate and authorize users.
try this code:
from django.contrib.auth.models import auth
from django.contrib import messages
def signin(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user:
auth.login(request, user)
return redirect('/')
else:
messages.info(request, 'Invalid credentials!!')
return redirect('signin')
else:
return render(request, 'signin.html')
In default, the Django authentication system provided in django.contrib.auth requires the end user to authenticate themselves using a username and password.
If you're using email and password for user authentication, you need a custom authentication backend. This link will help you.
Link : https://stackoverflow.com/a/37332393/9563316
If you use username and password for user authentication. You should try something like this.
from django.contrib.auth import authenticate, login
from django.contrib import messages
def userLogin(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('somewhere-you-want')
else:
messages.error(request, 'Invalid user login credentials!')
return redirect('userLogin')
else:
return render(request, 'login.html')
See docs here : https://docs.djangoproject.com/en/3.0/topics/auth/default/

Categories

Resources