I am a beginner in Django and I am working on a project which requires Custom user model as I Don't require is_staff, is_superuser, is_admin.
So, but searching and other ways I made my own Custom user model. But it is not working and I am stuck on it for days.
It will be a huge help if someone can help me with the code.
settings.py
AUTH_USER_MODEL = 'accounts.Usermanagement'
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'accounts.backends.EmailAuthBackend',
]
backends.py
#backends.py
# from django.contrib.auth.models import User
from django.contrib.auth.hashers import check_password
from django.contrib.auth import get_user_model
Usermanagement = get_user_model()
class EmailAuthBackend:
def authenticate(self,request,username=None,password=None):
print(request)
try:
user = Usermanagement.objects.get(emailid=username)
print(password)
print(user.password)
# print(check_password(password))
# print(user.check_password(password))
if user.check_password(password):
return user
return None
except user.DoesNotExist:
return None
def get_user(self,user_id):
try:
return user.objects.get(pk=user_id)
except user.DoesNotExist:
return None
views.py
# views.py
def loginPage(request):
# POST
if request.method == 'POST':
form = AuthenticationForm(request,data=request.POST)
# loginPage.html the html tag has attribute name = username for email ,
# name = password for password
if form.is_valid(): # Form Valid
email = request.POST['username']
password = request.POST['password']
#Check
print("EMAIL: ",email)
print("PASSWORD: ",password)
# Authentication USER
user = authenticate(request,username=email,password=password)
print("Authenticated ",user) # Check
# check
print(user)
if user is not None: # If User found
login(request,user,backend='accounts.backends.EmailAuthBackend')
messages.info(request, f"You are now logged in as {email}.")
return redirect("home")
else: # If User Not found
messages.error(request,"User not found")
return HttpResponse("User not found, not able to login")
else: # Form InValid
messages.error(request,"Invalid username or password.")
return HttpResponse("Form Invalid")
# GET
else:
form = AuthenticationForm()
context = {"form":form}
return render(request,"loginPage.html",context=context)
urls.py and other configurations are correct.
Problems:
check_password : always False
In DB I have unencrypted password ( ex:- password=admin )
DB is a legacy(existing) DB , so I first made the DB and then I did "python manage.py inspectdb" , which created models for me and then I changed few things, but did not changed the field names or the db_table name.
I am very much ok to create user through SHELL.
In loginPage.html the html tag has attribute name = username for email , name = password for password
if any other requirements I will edit the Questions
i think you cannot use the check_password function in your case, because it has been created for encrypted password case. Just make a user.password == password in your EmailAuthBackend
For second problem with get_user(), I think your userId is not the primary key for Django maybe, problem probably can be solved by filter directly by userId:
def get_user(self, user_id):
try:
return user.objects.get(userId=user_id)
except User.DoesNotExist:
return None
Concerning the problem No.2
Remove the password=password in your user=self.model()
It's making it difficult to make reference to the password in your user.set_password()
Related
I am making a custom reset password module. I am checking the old password with django auth User model. But check_password is always returning false. Please help if there is mistake in my logic.
views.py
def user_pass_change(request):
pass_old = request.POST.get('old_pass')
hash_pass_new = make_password(request.POST.get('new_pass'))
username = request.POST.get('username')
user = User.objects.get(username=username)
if user:
check = check_password(user.password,pass_old)
if check:
User.objects.filter(username=username).update(password=hash_pass_new)
messages.success(request, 'Password changed !')
return redirect('/login')
else:
messages.warning(request, 'Wrong old password')
return redirect('/login')
else:
messages.warning(request, 'Invalid Username !')
return redirect('/login')
I have tried including these hashers in setting.py
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher',
]
Thanks in advance
user.password is HASH of the password and not the actual password. check_password expects a raw string. [Django Docs]
To check if the current password is same as the pass_old you can do this:
check = user.check_password(pass_old) # user is the User object
I'm transferring a database to a new project and more precisely the users.
Don't ask me why but the passwords in the old database were hashed with md5 and then with sha256.
I'm using django-rest-auth to manage login.
url(r'^api/rest-auth/', include('rest_auth.urls')),
I added a custom authentication method:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'users.auth.OldCustomAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
)
}
Here is my auth file:
class OldCustomAuthentication(BaseAuthentication):
def authenticate(self, request):
try:
password = request.POST['password']
email = request.POST['email']
except MultiValueDictKeyError:
return None
if not password or not email:
return None
password = hashlib.md5(password.encode())
password = hashlib.sha256(password.hexdigest().encode())
try:
user = User.objects.get(email=email, password=password.hexdigest())
except User.DoesNotExist:
return None
# User is found every time
print('FOUND USER', user)
return user, None
But I still get an error when I request http://apiUrl/rest-auth/login/:
{
"non_field_errors": [
"Unable to log in with provided credentials."
]
}
Do you have any idea? Or maybe I'm doing it in a wrong way.
Thank you in advance.
Jeremy.
Following the advice of #MrName I managed to solve my issue.
So I deleted DEFAULT_AUTHENTICATION_CLASSES in my settings and added this:
REST_AUTH_SERIALIZERS = {
'LOGIN_SERIALIZER': 'users.auth.LoginSerializer'
}
Then I copy pasted the original serializer and modified the function _validate_email with:
def _validate_email(self, email, password):
user = None
if email and password:
user = self.authenticate(email=email, password=password)
# TODO: REMOVE ONCE ALL USERS HAVE BEEN TRANSFERED TO THE NEW SYSTEM
if user is None:
password_hashed = hashlib.md5(password.encode())
password_hashed = hashlib.sha256(password_hashed.hexdigest().encode())
try:
user = User.objects.get(email=email, password=password_hashed.hexdigest())
except ObjectDoesNotExist:
user = None
else:
msg = _('Must include "email" and "password".')
raise exceptions.ValidationError(msg)
return user
I have a weird problem here. When I login, it works well as expected but when I try to logout and try to login again, it says that my password is invalid.
I checked my User table and it's really changing my password everytime I use authenticate() function.
I got this error a month ago (still django 1.8 at that time) but gone after many testing and tracing and praying and didn't have a single idea what happened. It only occurs in my local machine though.
authentication.py
after authenticate() function, my password is already changed (tried to put a breakpoint after the function so I know for sure that this is the culprit).
from django.contrib.auth import authenticate, logout, login
def signin(request):
if request.method == "POST":
result = {}
data = req_data(request)
try:
user = authenticate(username = data['email'], password = data['password'])
if user:
if user.is_active:
login(request, user)
#return success for redirection
else:
raise ValueError("This user is inactive. Please contact your admin.")
else:
raise ValueError("Invalid username/password.")
except Exception as e:
return HttpResponse(e, status = 400)
else:
return redirect("login")
def signout(request):
logout(request)
return redirect("login")
#gets the params from ajax post
def req_data(request):
return json.loads(request.body.decode("utf-8")) if request.body.decode("utf-8") else {}
I checked the DB and got this result.
Old Password
pbkdf2_sha256$20000$N4esMaOT5BYi$nIehHw63b+iZSz2Vmu1hEO10BqPfzAGu1cZA1ci/nXI=
New Password (After login)
pbkdf2_sha256$24000$KVZeuG4pgSkv$VIenbuq0Wk8sYZros4kE4Q7W0Jt+bOC23ha4/VSOXV8=
EDIT:
for the meantime, I am not using authenticate() and just use a generic password.
username = data.get('email',"")
password = data.get('password',"")
if password == "genericpassword123":
try:
user = User.objects.get(email = username)
user.backend = 'django.contrib.auth.backends.ModelBackend'
except User.DoesNotExist:
raise ValueError("Invalid username/password.")
else:
user = authenticate(username = username, password = password)
if user:
if user.is_active:
login(request, user)
#return success for redirection
else:
raise ValueError("This user is inactive. Please contact your admin.")
else:
raise ValueError("Invalid username/password.")
Python 2.7
Django 1.9
Postgre 9.4
Thanks!
It's working now. I never thought that it works in different account with different password.
I have the following code and I get an error saying: "the User object has no attribute POST"
def login (request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(user)
return render(request, 'base_in/base_in.html', {})
else:
return render(request, 'signupapp/error.html', {'message':'the acount is not active'})
else:
return render(request, 'signupapp/error.html', {'message':'username and password is incorrect'})
I also tried this code and got another error: "login() takes 1 positional argument but 2 were given"
def login (request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(user)
return render(request, 'base_in/base_in.html', {})
else:
return render(request, 'signupapp/error.html', {'message':'the acount is not active'})
else:
return render(request, 'signupapp/error.html', {'message':'username and password is incorrect'})
What am I doing wrong? Based on django tutorials it should work properly:
https://docs.djangoproject.com/en/1.9/topics/auth/default/#how-to-log-a-user-in
What happened is you try to call login of from django.contrib.auth, but you are also defining your own function called login(), you have a kind of name conflict here.
You should rename that to something else, e.g. login_view()
from django.contrib.auth import authenticate, login
def login_view(request): # If you call it login,
# you get conflict with login imported aove
# The rest of your code here
# now if you call login(user), it will use the correct one,
# i.e. the one imported from django.contrib.auth
If you prefer not to rename, you can import Django's login under a different name, e.g.
from django.contrib.auth import login as auth_login
# Then use auth_login(user) in your code
I would advise adding a login form first
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)#hides password on input
then
from django.http import HttpResponseRedirect,HttpResponse
from django.contrib.auth import authenticate, login
.
.
def user_log(request):
#if you add request.method=='POST' is it a bug i dont know y
if request.method:
form = LoginForm(request.POST)
if form.is_valid():
cleandata=form.cleaned_data
#authenticate checks if credentials exists in db
user=authenticate(username=cleandata['username'],
password=cleandata['password'])
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect("your template")
else:
return HttpResponseRedirect("your templlate")
else:
return HttpResponse("Invalid login")
else:
form=LoginForm()
return render(request, 'registration/login.html',{'form':form})
I am new to Django, please help me how to implement Password Reset so that new password must be different from any of the last four passwords user has submitted in django :
I am using default django password reset:
urls.py:
url(r'^password/reset/$',auth_views.password_reset,
name='auth_password_reset'),
django/contrib/auth/views.py:
#csrf_protect
def password_reset(request, is_admin_site=False,
template_name='registration/password_reset_form.html',
email_template_name='registration/password_reset_email.html',
subject_template_name='registration/password_reset_subject.txt',
password_reset_form=PasswordResetForm,
token_generator=default_token_generator,
post_reset_redirect=None,
from_email=None,
current_app=None,
extra_context=None):
if post_reset_redirect is None:
post_reset_redirect = reverse('django.contrib.auth.views.password_reset_done')
if request.method == "POST":
form = password_reset_form(request.POST)
if form.is_valid():
opts = {
'use_https': request.is_secure(),
'token_generator': token_generator,
'from_email': from_email,
'email_template_name': email_template_name,
'subject_template_name': subject_template_name,
'request': request,
}
if is_admin_site:
opts = dict(opts, domain_override=request.get_host())
form.save(**opts)
return HttpResponseRedirect(post_reset_redirect)
else:
form = password_reset_form()
context = {
'form': form,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
Should I create database table to store all the previous passwords of the user or is there any django library which will provide me this feature.
Yes, you can create a model and store all the passwords of a user whenever password reset/changed.
from django.contrib.auth.models import User
import json
class OldPasswords(models.Model):
user = model.ForeignKey(User)
pwd = models.CharField(max_length=200)
def setPasswords(self, pwd):
self.pwd = json.dumps(pwd)
def getPasswords(self):
return json.loads(self.pwd)
create a signal while password reset/changed and save current password.
for example:
from allauth.account.signals import password_changed, password_reset
def send_password_changed_email(sender, **kwargs):
user = kwargs.get('user')
if user:
pwds = OldPasswords.objects.get_or_create(user=user)
pwds.setPasswords(pwd)
After saving to the model, you need to implement custom validator to show validation message when user try the old password while reset:
validate(self, password, user=None): validate a password. Return None if the password is valid, or raise a ValidationError with an
error message if the password is not valid. You must be able to
deal with user being None - if that means your validator can’t run,
simply return None for no error.
get_help_text(): provide a help text to explain the requirements to the user.
Any items in the OPTIONS in AUTH_PASSWORD_VALIDATORS for your validator will be passed to the constructor. All constructor arguments should have a default value.
Here’s a basic example of a validator, with one optional setting:
from django.core.exceptions import ValidationError
from yourapp.model import OldPasswords
from django.utils.translation import ugettext as _
class PasswordValidator(object):
def __init__(self, password):
self.password = password
def validate(self, password, user=None):
pwd_list = OldPasswords.objects.get(user=user).getPasswords()
if password in pwd_list:
raise ValidationError(
_("You used this password recently. Please choose a different one."),
code='password_recently_used',
params={'min_length': self.min_length},
)
def get_help_text(self):
return _(
"You used this password recently. Please choose a different one."
)
However, if you decide to store a user’s previous passwords, you should never do so in clear text.