Way to use email as the authentication field? - python

I am using django's inbuilt authentication system. Everything seems to be working fine. There are two fields that the user is requested to input at the time of signup: username and email. While logging in they are required to enter username and password.
I'd like to change this behavior so that username field is gone. I want to treat the email as the users username. So while signing in user will be required to put email / password
Is this possible while still using django's inbuilt auth system? I'm on django 1.7
Update
I had the need to add additional fields so I added the following to models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
telephone_number = models.CharField(max_length=100)
website_url = models.CharField(max_length=100)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

The answer is directly in django documentation, in short words you should subclass AbstractBaseUser or AbstractUser (in second case you can't totally remove username field), create your own user manager based on BaseUserManager or UserManager and customize built-in auth forms if you're using it (or any app that you're using is using it).

This is not strictly cannon, but to avoid creating a new User class or Auth backend, I tend to let users log in with both username or email.
Anyways you'll want to ensure emails are unique as django does not check this by default.
You'll then have to override the default login view to support this. You can create something along the lines of:
class EmailUsernameLoginView(View):
def post(self, request):
next = request.POST.get('next', None)
username = request.POST.get('username', None)
password = request.POST.get('password', None)
error = ''
if username and password:
try:
usr = User.objects.get(email=username)
username = usr.username
except User.DoesNotExist:
pass # If the user doesn't exist, it's an username
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect(next)
else:
error = 'Your account is not active'
else:
error = 'The username / email - password comb is wrong'
else:
error = 'Please provide a username / email and password'
ctx = {'error': error} # Fill with needed feedback
return render(request, ctx, 'registration/login.html')
This is just a draft and you should probably include a form to help with validation / cleaning

Related

Django Testing - authenticate() returns None

Working on making some unittests with Django, and trying to make some testing with the login process with the login form.
I am using modified User model just to make the email field unique; otherwise nothing drastically different.
account/views.py
def post(self, request):
# Retrieve the username and password
username = request.POST['username']
password = request.POST['password']
# Create a user object from authentication, or return None
user = authenticate(username=username, password=password)
# Check if user was created
if user is not None:
# Rest of the code, irrelevant...
account/test_views.py
from account.models import User as CustomUser
# Code snippit
def test_account_login_POST_successful_login(self):
# Create a user to test login
CustomUser.objects.create_user(
username='test_user',
email='test_user#intranet.com',
password='flibble'
)
response = self.client.post(self.login_url, {
'username': 'test_user',
'password': 'flibble'
})
self.assertEqual(response.status_code, 301)
account/models.py
class User(AbstractUser):
# Make the email field unique
email = models.EmailField(unique=True)
project/settings.py
# Authentication
AUTH_USER_MODEL = 'account.User'
Funny thing is that login works normally on the web app, but when testing it always returns None.
I've tried to check_password() with the created user, and it returns true in both the test method and the view method.
I've also tried putting in AUTHENTICATION_BACKEND = ['django.contrib.auth.backends.ModelBackend'], but no go.
I faced with the same problem. The problem was in is_active model field. In my case this field was False by default, so authenticate() returns None all the time.

How can i create custom users with only forms?

I am a beginner in Django an am using version 2.2 .I created a user form to sign a user in the site but it cant add other field information to the database
I have tried adding other fields in the fields list add adding fields but nothing works`
forms.py
from django import forms
from django.contrib.auth import (
authenticate,
get_user_model
)
User = get_user_model()
class UserRegisterForm(forms.ModelForm):
username = forms.CharField(label='PUsername')
email = forms.EmailField(label='Email address')
email2 = forms.EmailField(label='Confirm Email')
password = forms.CharField(widget=forms.PasswordInput,label='Password')
password2 = forms.CharField(widget=forms.PasswordInput,label='ConfirmPassword')
age = forms.CharField(label='your age')
info = forms.CharField(label='info about you')
class Meta:
model = User
fields = [
'username',
'email',
'email2',
'password',
'password2',
'age'
'info'
]
def clean(self, *args, **kwargs):
username = self.cleaned_data.get('email')
email = self.cleaned_data.get('email')
email2 = self.cleaned_data.get('email2')
password = self.cleaned_data.get('password')
password2 = self.cleaned_data.get('password2')
if email != email2:
raise forms.ValidationError("Emails must match")
email_qs = User.objects.filter(email=email)
if password != password2:
raise forms.ValidationError("Passwords must match")
email_qs = User.objects.filter(email=email)
if email_qs.exists():
raise forms.ValidationError(
"This email has already been registered")
username_ex = User.objects.filter(username=username)
if username_ex.exists():
raise forms.ValidationError("This username is taken")
return super(UserRegisterForm, self).clean(*args, **kwargs)
views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate,get_user_model,login,logout
from .forms import CreateUserForms
import random
import string
def register_view(request):
if request.method=='POST':
frm=CreateUserForm(request.POST)
if frm.is_valid():
username, email, password = frm.cleaned_data['username'], frm.cleaned_data['email'], frm.cleaned_data['password1']
new_user = User.objects.create_user(username, email, password)
new_user.is_active = True # if you want to set active
new_user.save()
else:
frm=CreateUserForm()
return render(request,'registration/signup.html',{'form':frm})
def logout_view(request):
logout(request)
return redirect('/')
Expected results are the working form,but actual results are only saving the username, password and email
read the documentation on python super . you are using it in wrong way. calling super at last of the clean method mean it it execute the modelform clean method and code before super get modified .
The title of your question is
How can i create custom users with only forms?
The answer to that is: That's not possible. Whatever you want to save to the database, you have to have a corresponding model for it. Forms only determine what data is submitted by the clients and how that data is processed.
So if you want to save columns age and info for your users, you'll have to create a Model and the corresponding table and columns in your database to hold these values.
Now, the default Django User model only takes username, email and password (plus some booleans like is_staff, is_superuser, is_active etc...). If you want to save additional information, you have a few options that are well described in the official docs, either by extending the default User model or by substituting it.
The recommendation when starting a new Django project is to always at least substitute with your own User model (see this). If you will only ever have one type of user, then add the age and info fields on your custom User model. But if there's any chance that you might have different types of users where age and info might not be relevant in the future, extend your custom User model with a profile.

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/

Django: Not allowing newly-created user to log in until he/she is approved by the admin?

I am recently trying to develop a website using Django in which a person can make his/her registration in the system but he/she should not be allowed to log in to the system until the admin approves the request. I tried the user.is_active field but the only thing it does is to prevent the new user to have access as admin. In other words, the system gives him/her permission to log in the system. My code is as follows:
# create a new user but he will be inactive until admin's approval
user = User.objects.create_user(username=username, password=password)
user.is_active = False
After changing the is_active field of the user to False I try to log in the system using the new user's username and password and the system lets me in. This is my code for the login:
def login(request):
context = RequestContext(request)
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username = username, password = password)
if user is not None and request.user.is_active:
auth.login(request, user)
print 'login'
print request.user.username
print request.user.is_active
return redirect('app.views.results')
else:
print 'no login'
return render(request, 'login.html')
When I print the user's username and is_active field, I see that the "is_active" field is True instead of False. Is something wrong with the code or am I missing something?
Any better approaches to solve the problem will also be welcome and appreciated.
After you perform value assignment for model objects' attributes, you should call object.save(), as so:
user = User.objects.create_user(username=username, password=password)
user.is_active = False
user.save()
This will save the changes you've introduced to the object.
From Django docs

Convert Django ModelForm to use User object

I'm creating a registration form for my site.
I'm going with just the standard field entries of username, email, password in my User object.
The database tables are already created.
Models.py
class RegistrationForm(ModelForm):
class Meta:
model = User
views.py
def Registration(request):
RegForm = RegistrationForm(request.POST or None)
if request.method == 'POST':
if RegForm.is_valid():
newUser = User.objects.create_user(username, email, password)
RegForm.save()
try:
return HttpResponseRedirect('/Newuser/?userNm=' + clearUserName)
except:
raise ValidationError(('Invalid request'), code='300') ## [ TODO ]: add a custom error page here.
My question is, how do I represent these fields:
username, email, password
in this line (from the view):
newUser = User.objects.create_user(username, email, password)
that are part of the RegistrationForm() in models.py ?
Additionally: How do I properly represent this default model (User) in the modelform in forms.py?
To answer your second question:
Use UserCreationForm to represent registration process for User class, it handles validation and saving for you and you can always extend it (i.e. to add email field)
User class has a lot of related forms, depending of the use case: authentication, registration, password change etc. read the docs on authentication to find more.
https://docs.djangoproject.com/en/1.5/topics/auth/default/#module-django.contrib.auth.forms
You can get the validated data from the form using cleaned_date:
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
newUser = User.objects.create_user(username, email, password)
Now I think your approach has serious problems since you are saving the form again after creating the user object, also the User object expects the password field to be a hash of the password and some meta data, etc.
I highly recommend you use django-registration (or at least have a look at it) which handles all this stuff for you in addition to email validation, all you need is to provide the templates(and also you can find some templates for it like this )

Categories

Resources