I am having an issue with Django users changing passwords - I have built a few production sites in Django, just none in about a year (or in 1.8), but I don't recall having this issue before.
Summary
When a user changes their password, the user is logged out, but the password is successfully changed.
Details
I have a view that allows a user to change a password, I am using standard django forms and the auth framework, and to stress: changing the password works, it just logs the user out so that they have to login again.
I actually don't mind this terribly, I would prefer that the user be redirected to their dashboard with a message update, if i need to reauth the user in the code, then I will, just seems kind of clunky.
here is my view function:
#login_required
def user_change_password(request):
"""Allows a user to change their password"""
if request.method == "POST":
form = SubscriberPasswordForm(request.POST)
if form.is_valid():
try:
request.user.set_password(form.cleaned_data['password'])
request.user.save()
except Exception, err:
print "Error changing password: {}".format(err)
messages.add_message(request, messages.ERROR, 'The password could not be changed, please try again '
'later. This admins have been notified of this error.')
else:
#this outputs True
print request.user.is_authenticated()
messages.add_message(request, messages.INFO, 'Your password has been changed successfully')
return HttpResponseRedirect("/accounts/dashboard/")
else:
form = SubscriberPasswordForm()
return render(request, "accounts/change-password.html", {"form": form})
So the password is changed, the user gets redirected to the dashboard page, the #login_required decorator then redirects them back to the login screen.
The password form is here, though it is pretty straightforward.
class SubscriberPasswordForm(forms.Form):
password = forms.CharField(widget=forms.PasswordInput)
cpassword = forms.CharField(widget=forms.PasswordInput)
def clean_cpassword(self):
password1 = self.cleaned_data.get("password")
password2 = self.cleaned_data.get("cpassword")
if password1 and password2 and password1 != password2:
raise forms.ValidationError(
self.error_messages['password_mismatch'],
code='password_mismatch',
)
For django 1.9:
from django.contrib.auth import update_session_auth_hash
def password_change(request):
if request.method == 'POST':
form = PasswordChangeForm(user=request.user, data=request.POST)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user)
The following fields must be supplied in the POST request:
old_password
new_password1
new_password2
See detailed docs at update_session_auth_hash
My understanding is being logged out after password change is new in Django 1.7. So you will need to re-auth user in your code as you said.
See Release Notes:
https://docs.djangoproject.com/en/1.8/releases/1.7/#django-contrib-auth
Here is the specific note:
"The AbstractBaseUser.get_session_auth_hash() method was added and if your AUTH_USER_MODEL inherits from AbstractBaseUser, changing a user’s password now invalidates old sessions if the SessionAuthenticationMiddleware is enabled. See Session invalidation on password change for more details including upgrade considerations when enabling this new middleware."
See Documentation:
https://docs.djangoproject.com/en/1.7/topics/auth/default/#session-invalidation-on-password-change
For Django 1.8
Simply call update_session_auth_hash after set_password like so:
from django.contrib.auth import update_session_auth_hash
request.user.set_password(form.cleaned_data['password'])
update_session_auth_hash(request, request.user)
for Django 3, Django 1.8+ use this link:
https://docs.djangoproject.com/en/3.2/topics/auth/default/#django.contrib.auth.update_session_auth_hash
or use this code:
from django.contrib.auth import update_session_auth_hash
def password_change(request):
if request.method == 'POST':
form = PasswordChangeForm(user=request.user, data=request.POST)
if form.is_valid():
form.save()
update_session_auth_hash(request, form.user)
else:
...
Related
I am creating a user profile using django’s authentication system (from django.contrib.auth.models import User). Before this I am trying to extend the field of user using an extra field (i.e- userprofile= ceo/developer/marketinghead) in models.py. Here is my models.py file
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class extendeduser(models.Model):
userprofile_choice=(
('ceo', 'ceo'),
('developer', 'developer'),
('marketinghead', 'marketinghead'),
)
userprofile=models.CharField(choices= userprofile_choice, max_length=255, blank=False)
user=models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.userprofile
now I am sucessfully registering the new user. Now I have created differrent html pages based on their profile. So at the time of login I take an extra input from user which is userprofile. And based on this I have created views.py for redirecting the user at correct place. Here is my views.py file :-
def login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
uf = request.POST['userprofile']
user = auth.authenticate(username=username, password=password)
user_profile = extendeduser.objects.filter(user = user)
# print(user_profile[0])
# print(uf)
# print(user.get_username)
# print(user.__dict__)
#print(user.get_userprofile)
if user is not None:
if uf==user_profile[0]:
if uf=='ceo':
auth.login(request, user)
messages.success(request, "You are logged-In")
return redirect('wtoday')
elif uf=='developer':
auth.login(request, user)
messages.success(request, "You are logged-In")
return redirect('swhome')
elif uf=='marketinghead':
auth.login(request, user)
messages.success(request, "You are logged-In")
return redirect('sswhome')
else:
messages.warning(request, 'Invalid Credentials!!')
return redirect('login')
else:
messages.warning(request, 'Invalid Credentials!')
return redirect('login')
else:
messages.warning(request, 'Invalid Credentials')
return redirect('login')
return render(request, 'accounts/login.html')
Everything is fine but this "if uf==user_profile[0]:" line of code is not working. basically it is checking that the "userprofile" field of any particular user which is store in database is same as at the time of login or not. I am saying this line of code is not working because when i comment that line and then without checking user profile from the databae i just redirecting them based on the data which he fiels at the time of login then it works. But I didn't want this.
Please help me out!!
You can't compare uf and userprofile[0], because uf is a string and userprofile[0] is an extendeduser object. Maybe if uf == str(userprofile[0]): is what you want.
I write some code to register a user. In my fonction "register(request)", Before i do email verification i save the user and he is saved in the database but he is not active. Then i use this user to activate him in my function "activate(request)" and i activate the user.
But there is a problem, if the user put a wrong or not email, he will be saved in database, and this can take useless memory space in database. And the other problem is that if the user want to correct his informations on registration page, he will not be able to do that because his username and email already exists in database.
EDIT
By saying that he puts a wrong email is in the case he put username#gmail.com instead of user_name#gmail.com. The email is entered and is in the good format but that is not his email
def register(request):
registered = False
if request.method == 'POST':
form = UserForm(data=request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
mail_subject = 'Activez votre compte acquisitor.'
message = render_to_string('users/acc_active_email.html',{
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': account_activation_token.make_token(user),
})
to_email = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[to_email]
)
email.send()
return render(request, 'users/mail_registration.html')
else:
print(form.errors)
else:
form = UserForm()
return render(request, 'users/registration.html', {'user_form': form,
'registered': registered})
def activate(request, uidb64, token, backend='django.contrib.auth.backends.ModelBackend'):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
registered = True
user.save()
login(request, user, backend)
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse("Lien d'activation invalide")
if the user put a wrong or not email
Your form should validate that the email field is filled and at least formally correct, so the only possibility is that the user mistyped his email. A common and effective solution (albeit slightly annoying from user's perspective) is to put 2 email fields in the form and check if they match in the form's clean() data.
At this point, if the user still managed to get it wrong, he won't get the activation mail anyway, so there's not much you can do - except eventually adding a cron job to remove users that never activated their accounts (based on active status, creation date and last login date).
Apologies if this is simple or my terminology is off, this is my first django project. I haven't been able to find a similar solution for this online.
I have an existing application, with a postgres DB where I authenticate my users. I have wrote an application in Django to interact with some tables and display info to the user. I would like to use Django to login and track User sessions against this DB. so I can use the features like
{% if user.is_authenticated %}
but I don't want to use the migrate command so I don't want to change the existing DB. I can access the table where the account info is as I created a model for it.
I see you can use remote user logon param but I cant find any sample or guide on how to use it and am completely lost.
Right now I create a login form in the views page. Then get the username and password that is entered, but I don't know what to do next. Also would need to hash the password. Is there a libray in djano that will do that for the app.
Any pointers or online guides for this would be appreciated.
Here is the views for login
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
email = form.data['account_email']
password = form.data['account_password']
user = authenticate(username=email)
if user.check_password(password):
login(request, user)
return redirect('myapp:cust_select')
else:
# Username and password did not match
raise ValidationError('Invalid Username/Password')
return render(request, 'myapp/login.html', {'form' : form}
backends.py
from django.conf import settings
from django.contrib.auth import get_user_model
class UserAuthBackend(object):
def authenticate(self, username=None, password=None):
try:
account = get_user_model()
user = account.objects.get(account_email=username)
if user:
return user
except account.DoesNotExist:
print "account not found"
return None
def get_user(self, user_id):
try:
account = get_user_model()
return account.objects.get(pk=user_id)
except User.DoesNotExist:
return None
models.py
class Accounts(AbstractUser):
account_id = models.AutoField(primary_key=True)
account_email = models.CharField(max_length=100)
account_password = models.CharField(max_length=20)
def __str__(self):
return self.account_email
class Meta:
managed = False
db_table = 'accounts'
settings.py
AUTHENTICATION_BACKENDS = ( 'myapp.backends.UserAuthBackend', )
Its keeps exiting with the same error in the sql query.
column accounts.password does not exist
LINE 1: SELECT "accounts"."password", "accounts"."last_login", "acco...
It doesnt appear to be using my Account model. It does select it from that table but how can i get it to stop requesting accounts.password and accounts.last_login as they dont exist in y Accounts model
For reference
Note: You need to do try, catch to get this code working
def login(request):
form = LoginForm()
if request.method == "POST":
form = LoginForm(request.POST)
if form.is_valid():
username = form.data['account_email']
password = form.data['account_password']
# First authenticate
user = authenticate(request, username=username, password=password)
if user is not None :
# Succeed, now log user in
login(request,user)
return redirect('myapp:select')
else:
# Username and password did not match
raise ValidationError('Invalid Username/Password')
return render(request, 'myapp/login.html', {'form' : form})
I have added python-social-auth in my project for social logins. I also have a signup form of my own for new users. For social logins, I added some authentication backends.
Now, the social logins are working fine, but the signup form causes some problems.
After I enter the details, and click signup, this error comes up.
I see in the admin panel, the user was added even after this error.
ValueError: You have multiple authentication backends configured and therefore must provide the `backend` argument or set the `backend` attribute on the user.
Now, it is asking me to set the backend attribute of the user. How to set that ?
Here is the view for signup,
def signup(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_pass = form.cleaned_data.get('password')
user = authenticate(username=username,password=raw_pass)
login(request,user)
return redirect('location:get_location')
else:
form = SignupForm()
return render(request, 'signup.html', {'form':form})
Worked for me:
if request.method == 'POST':
form = UserCreateForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user, backend='django.contrib.auth.backends.ModelBackend')
return redirect('/')
else:
pass
I want to make login and registration for a custom user with only 5 fields: user name, name, password, linkedin id and mobile number.
I made registration successfully but I am stuck with login, I cannot authenticate my user.
Is there any way to authenticate my user, or how can I login?
Currently I am getting logged in by
user = Consultants.objects.get(Q(username= username) & Q(password= password))
But i want to make login by
user=authenticate(username=username,password=password)
Note:I don't want to use django default User Model For it.
Please help me in this.
Thanks in advance.
models.py
class Consultants(models.Model):
first_name=models.CharField(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)
mobile_no=models.CharField(max_length=255,blank=True,null=True)
linkedin_id=models.CharField(max_length=255,blank=True,null=True)
is_active=models.BooleanField(default=False)
views.py
def register(request):
context = RequestContext(request)
registered = False
print "inside register view"
if request.method == 'POST':
consultant_form = ConsultantsForm(data=request.POST)
if consultant_form.is_valid():
consultant = consultant_form.save(commit=False)
consultant.save()
registered = True
else:
print consultant_form.errors
else:
consultant_form = ConsultantsForm()
return render_to_response(
'register.html',
{'consultant_form': consultant_form, 'registered': registered},
context_instance=RequestContext(request))
def login_user(request):
context = RequestContext(request)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
print type(username)
try:
user = Consultants.objects.get(Q(username= username) & Q(password= password))
user = authenticate(username=username, password=password)
if user.is_active:
user.backend = 'django.contrib.auth.backends.ModelBackend'
login(request, user)
a= request.user.username
return HttpResponse("welcome......you are succesfuly log in")
else:
return HttpResponse("Your account is disabled.")
except ObjectDoesNotExist:
return HttpResponse("INvalid User")
Note:I don't want to use django default User Model For it Please help
me in this. Thanks inadvance
Is your Consultants class inheriting from the base Django user class?
The authenticate() function is used to authenticate the base user model, you may not be setting a password for the user when they are created?
Another way to go about this would instead create a Profile model with all of these extra fields with a OneToOneField to the base user model, and authenticate though the Django ORM.
I think it's better to inheriting from django embedded user class, you can follow these steps:
extend your custom user class from AbstractBaseUser and PermissionsMixin
Assign and fill this config in settings.py:
AUTH_USER_MODEL = 'YOUR_CUSTOM_CLASS_IN_FULL_QUALIFIED_NAME' e.g.: 'your_app_name.Consultants'
Voila, you can use django default user crud, also authentication