I'm a beginner in Django. I have a signup form with only 2 fields. Username and Password. The password is encrypted using the pbkdf2_sha256 algorithm.
I want to login using the username and password.so the password that I'm inputting in the login page must be checked with the encrypted password. How to do that?. Also, please explain what authenticate and check_password function does?
def save(request):
if request.method == 'POST':
name = request.POST.get('name')
password = request.POST.get('pass')
enc_pass = pbkdf2_sha256.encrypt(password,rounds=12000,salt_size = 32)
a = signup(username = name, password = enc_pass)
a.save()
return render(request,'save.html')
def login(request):
if request.method == 'POST':
username = request.POST.get('user')
password1 = request.POST.get('password1')
p = check_password(password=password1)
if signup.objects.filter(username__exact=username).exists() and p is True:
return HttpResponse("Success")
else:
return HttpResponse("Invalid Credentials")
return render(request, 'login.html')
You can do:
if check_password(password_user_entered, request.user.password):
# You can authenticate
Here, password_user_entered is password that came from the request(or, pw to be checked). And, request.user.password which is the password with which we want to compare.
check_password does not work like this. To make it work, you need to use Django's own authentication system. If you are concerned about using pbkdf2_sha256, Django provides this hasher. To use this with you own auth system, add it to settings:
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.Argon2PasswordHasher',
]
And in django authentication, you do not need to hash it manually, django will take care of it itself. All you need to do is save the user like this:
from django.contrib.auth.models import User
user = User.objects.create_user(username=username, email=email, password=password, #.. other required fields)
And to check password:
user = User.objects.get(username=username)
user.check_password(password)
More information can be found in documentation
Related
I'm having trouble when i try to update user password in django.
def password(request):
if request.method=="POST":
password =request.user.password
username=request.user.username
c_password=request.POST["current_password"]
new_password=request.POST["new_password"]
r_new_password=request.POST["retype_new_password"]
if password==c_password:
if new_password==r_new_password:
user =User.objects.get(username=username)
user.set_password(new_password)
user.save()
messages.info(request,"Successfully saved")
else:
messages.info(request,"PASSWORD DOES NOT MATCH")
else:
messages.info(request,"PASSWORD INCORRECT")
return render(request,"security.html")
When i fill the current password, it is giving me error password incorrect. But, when i fill pbkdf2_sha256$320000$Cb4s4nwqKwirdgo50ZdjLH$aeuSP3X+dSZXsv0XJB0XxkpwfsmU+PedMX9Jl50Zark=
, my password becomes correct and user password is updateable. My problem is I would like to fill in current password field as normal current password without getting the error.
You use authenticate(…) [Django-doc] to validate the password: this will retrieve the hashing algorithm and the salt, and check if the hashes match, so you can work with:
def password(request):
if request.method == 'POST':
c_password = request.POST['current_password']
new_password = request.POST['new_password']
r_new_password = request.POST['retype_new_password']
user = authenticate(username=request.user.username, password=c_password)
if user is not None:
if new_password == r_new_password:
user.set_password(new_password)
user.save()
messages.info(request, 'Successfully saved')
else:
messages.info(request, 'PASSWORDS DOE NOT MATCH')
else:
messages.info(request, 'PASSWORD INCORRECT')
return render(request, 'security.html')
There is however a PasswordChangeView [Django-doc] to change the password: this already implements the logic and uses a form. You can inject a different template, for example with:
path(
'password/change/',
PasswordChangeView.as_view(template_name='security.html'),
name='password_change'
)
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: It is better to use a Form [Django-doc]
than to perform manual validation and cleaning of the data. A Form will not
only simplify rendering a form in HTML, but it also makes it more convenient
to validate the input, and clean the data to a more convenient type.
Refer the Documentation Django does not store raw (plain text) passwords on the user model
use authenticate function instead of using if password==c_password:.
from django.contrib.auth import authenticate
def password(request):
if request.method=="POST":
password =request.user.password
username=request.user.username
c_password=request.POST["current_password"]
new_password=request.POST["new_password"]
r_new_password=request.POST["retype_new_password"]
user = authenticate(username=username, password=c_password)
if user is not None:
if new_password==r_new_password:
user =User.objects.get(username=username)
user.set_password(new_password)
user.save()
messages.info(request,"Successfully saved")
else:
messages.info(request,"PASSWORD DOES NOT MATCH")
else:
messages.info(request,"PASSWORD INCORRECT")
return render(request,"security.html")
Hey everyone I have a couple questions in regards to refactoring some old api endpoints as far as authentication goes. I have a view for example...
#csrf_exempt
# PARAMETERS: username, password
def submit_offer(request):
"""Submit an offer"""
username = request.GET.get("username")
password = request.GET.get("password")
# Authenticate user to set instance.user value into BuyerForm
user = authenticate(username=username, password=password)
if not user:
# Always want our potential Buyer to be logged in & authenticated
return JsonResponse({'message': 'Please login to continue.'})
if request.method == 'POST':
form = BuyerForm(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
# sets current user as Buyer.user
instance.user = user
instance.save()
return JsonResponse({'success': True}, status=200)
else:
data = form.errors.as_json()
return JsonResponse(data, status=400, safe=False)
else:
return JsonResponse(data={'status': 403})
Now every view that uses a form, and needs to grab the instance.user, has the same lines of code below...now I thought using request.user would do the job, but when testing that way I am getting back an AnonymousUser, which is kind of confusing me?
username = request.GET.get("username")
password = request.GET.get("password")
# Authenticate user to set instance.user value into BuyerForm
user = authenticate(username=username, password=password)
Now is there a better way to authenticate the user, like in a regular django view using request.user, rather than having to manually authenticate the user in each view? (edited)
password = request.GET.get("password").
This is very vulnerable way to design a django app.
Please see
Accessing Username and Password in django request header returns None
BTW, write a custom middle ware and put your code there.
username = get_username_from_header
password = get_password_from_header
# Authenticate user to set instance.user value into BuyerForm
user = authenticate(username=username, password=password)
# Attach user to request
request.user = user
As each request are being passed through the middle-ware, you can access the user from each view.
I am trying to create a user login. I am registering the user through django's admin page. Username and passwords are entered correctly.
Also I have tried adding authentication backends to settings.py
I have tried multiple ways but couldn't get it to work.
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
My code looks like below :
models.py :
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
views.py:
def login(request):
if request.method == 'POST':
username = request.POST.get('user')
password = request.POST.get('pass')
user = authenticate(username=username,
password=password) ----------> None
if user:
if user.is_active():
login(request, user)
return HttpResponseRedirect(reverse('index'))
else:
return HttpResponse('Account not active')
else:
print('Someone tried to login and failed ')
print('Username {} and passowrd {}'.format(username, password))
return HttpResponse('Invalid login details supplied!!')
else:
return render(request,'account/login.html', {})
The username and password from the below ones are coming as empty so it is giving none
username = request.POST.get('user')
password = request.POST.get('pass')
Try to inspect the element from HTML to find the name of the fields from which the data is coming from the template or print the values of username and password variables to cross verify.
use request.POST.get('username'), request.POST.get('password1') but as told it totally depends on the html template. It is safer to clean the data and then go for authentication.
Django has inbuilt Class Based Views for the same purpose. Give them a try
def user_login(request):
if request.method == "POST":
user_name = request.POST.get("username",'')
pass_word = request.POST.get("password",'')
user = authenticate(user_name=user_name,password=pass_word)
if user is not None:
login(request,user)
return render(request,'index.html')
else:
return render(request,'login.html',{ })
elif request.method == "GET":
return render(request,"login.html",{ })
I've already set up the super user and updated the database, but the backstage password user still returns None
authenticate function takes arguments in form:
authenticate(username='john', password='secret').
change
user_name -> username
in arguments
the default authenticate looks like this
from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
# A backend authenticated the credentials
else:
# No backend authenticated the credentials
so i think you need to change username if you're not overriding it
user = authenticate(username=user_name,password=pass_word)
In this line the authenticate function has username=user_name not user_name=user_name as argument. I think this might be the issue.
Hope this helps :-)
I am trying to use the django inbuilt AuthenticationForm to allow users to login using their email address and password. I have changed the authenticate function to accept both username and email to authenticate users.
This is my code so far:
def loginuser(request):
if request.POST:
"""trying to use AuthenticationForm to login and add validations"""
form = AuthenticationForm(request.POST.get('email'),request.POST.get('password'))
user = form.get_user()
if user.is_active:
login(request,user)
render_to_response('main.html',{'user':user})
else:
HttpResponse('user not active')
render_to_response('login.html')
But this is not how the authentication form is used, at least not the correct way.
An example. You can see django.contrib.auth.forms for derails (search AuthenticationForm in the file forms.py).
f = AuthenticationForm( { 'username': request.POST.get( 'email' ), 'password': request.POST.get( 'password' ) } )
try:
if f.is_valid():
login( f.get_user() )
else:
# authentication failed
except ValidationError:
# authentication failed - wrong password/login or user is not active or can't set cookies.
So, modify your code to:
def loginuser(request):
if request.POST:
"""trying to use AuthenticationForm to login and add validations"""
form = AuthenticationForm(request.POST.get('email'),request.POST.get('password'))
try:
if form.is_valid():
# authentication passed successfully, so, we could login a user
login(request,form.get_user())
render_to_response('main.html',{'user':user})
else:
HttpResponse('authentication failed')
except ValidationError:
HttpResponse('Authentication failed - wrong password/login or user is not active or can't set cookies')
render_to_response('login.html')