I was working with a legacy database where there was a table 'tbl_personaldetails', from where i ported data to custome user model.
In code to port data from tbl_personaldetails, i use user.set_password(password) which sets password as hash in user table.
Trouble is when i try to authenticate(username=username, password=password) where password and username are plain text, authenticate returns None (Even for superuser account from which i can login in admin section).
The code to login is as follows:
class LoginView(FormView):
form_class = LoginForm
template_name = 'account/login.html'
def get_success_url(self):
return reverse("userHomeAfterLogin")
def form_valid(self, form):
email = form.cleaned_data['email'].lower().strip()
password = form.cleaned_data['password']
user = authenticate(email=email, password=password)
if user:
login(self.request, user)
return redirect(self.get_success_url())
else:
try:
user = User.objects.get(email__iexact=email)
if not check_password(password, user.password):
form._errors['password'] = ErrorList([u'That is not the correct Password.'])
except User.DoesNotExist:
form._errors['email'] = ErrorList([u'This email is not registered with us.'])
context = self.get_context_data(form=form)
return self.render_to_response(context)
As of now it flows like this:
1.authenticate returns none, landing up in else part:
2. can retrieve the user with email and check_password is correct.
3. it renders the form w/o any error message
.
what is it that i am doing wrong, everything looks fine though
As far as I understand from the code snippet, you are using email as your username. With email address, Django's authenticate will never work. It expects username instead. See code below.
def authenticate(**credentials):
"""
If the given credentials are valid, return a User object.
"""
for backend in get_backends():
try:
user = backend.authenticate(**credentials)
except TypeError:
# This backend doesn't accept these credentials as arguments. Try the next one.
continue
if user is None:
continue
# Annotate the user object with the path of the backend.
user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
return user
In order to use email address as the username field, please refer to http://justcramer.com/2008/08/23/logging-in-with-email-addresses-in-django/.
Hope this helps.
Related
I'm working on a django application. The application has a dashboard. How can i make it so that everytime the user wants to access the dashboard, he/she has to confirm their identity, with the same password they use to log into the same application?
Thank you
#Verify that the USERNAME and PASSWORD combination exist USING THE AUTHENTICATE METHOD,
Views.py:
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
#IN YOUR CASE get the pwd using forms or something,
instance_password = request.post.get('the_pwd_field')
user = authenticate(request, username= request.user.username, password= instance_password)
if user is not None:
# REDIRECT TO THE DASHBOARD
else:
# FAIL CASE SCENARIO
In views.py
from django.contrib.auth.hashers import check_password
form = YourFormForPassword(request.POST or None)
if form.is_valid():
currentpasswordentered = form.cleaned_data.get("try_password")
currentpassword = request.user.password
authenticate_user = check_password(currentpasswordentered, currentpassword)
if authenticate_user:
# REDIRECT TO THE DASHBOARD
else:
#Redirect to other page or keep same login page
If you want, user to enter credentials explicitly before accessing the dashboard, then you have to return the "form" that accepts creds from user, when they try to access the dashboard.
def dashboard_login_view(request):
context = {}
if request.method == 'POST':
form = DashboardLoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get('dashboard_login_username').lower()
password = form.cleaned_data.get('dashboard_login_password')
authenticated = check_password(password)
if authenticated:
return HttpResponseRedirect(reverse('dashboard_view'))
else:
messages.error('User is not authenticated.')
return HttpResponseRedirect(reverse('login'))
else:
context['form_one'] = DashboardLoginForm()
return render(request, 'dashboardlogin.html', context)
In my project I have an open signup form, where you can create your Company and all the information bellow it.
After that you can invite people to help you administrate the information of your company. To do that, my idea was to, when the logged user add another admin, I would create the user manually with a fake password and send a Reset Password request to the created email, so he can create his own password. The important code is below:
from django.contrib.auth.forms import PasswordResetForm
...
def create_admin(request):
if request.method == 'POST':
form = AdminForm(request.POST)
if form.is_valid():
email = form.cleaned_data.get("email")
random_pass = User.objects.make_random_password()
user = User(username=email, email=email, password=random_pass)
user.save()
company.add_admin(user)
reset_form = PasswordResetForm({'email': email})
reset_form.save(
email_template_name="rh/password_reset_email.html",
subject_template_name="rh/password_reset_subject.txt")
return redirect('dashboard')
else:
form = AdminForm()
return render(request, 'rh/create_admin.html', {'form': form})
Unfortunately, the above code returns a Exception Type: AttributeError 'PasswordResetForm' object has no attribute 'cleaned_data'
To note:
I already have a fully working reset password feature, using everything from django and custom templates. That's why I'm trying to make this work this way
I would like to customize the email_template_name and subject_template_name, like in my code
thanks in advance
After a bit of dialog in comments I'll leave the response. The two issues were the way the password was being created and the form not being validated. This code should work:
email = form.cleaned_data.get("email")
random_pass = User.objects.make_random_password()
user = User(username=email, email=email)
user.set_password(random_pass)
user.save()
company.add_admin(user)
reset_form = PasswordResetForm({'email': email})
reset_form.is_valid()
reset_form.save(
email_template_name="rh/password_reset_email.html",
subject_template_name="rh/password_reset_subject.txt")
return redirect('dashboard')
(Note that in this code I used the form and not the view, because I'm not sure about what you did with that. If this code doesn't work please correct it.)
I am using django registration redux for login and auth purposes. I want to do the following.
if the user logs in for the first time i want to redirect to URL-"profile/create"
if the user is a returning user i dont want the user to access the URL-"profile/create" and i want the user to be redirected to another URL.
django-registration-redux seems to use Django's login-view for logging users in per default.
Thus I would provide a customized login view instead that additionally inspects the user that tries to log in and checks if last_login is already filled out.
Depending on the result the user then can be redirected to the desired page once the authentication succeeded.
in most basic form when user login first time it has to be registered.
do not use this kind of functionality at login use it at register function (view)
this is a old draft code that give you the idea
def ragister(request):
if request.user.is_authenticated:
return HttpResponseRedirect('/profile-settings/')
if request.method == 'POST':
fname = request.POST['fname']
lname = request.POST['lname']
username = request.POST['username']
password = request.POST['password']
users = User()
users.password = password
users.username = username
users.first_name = fname
users.last_name = lname
try:
users.set_password(password)
users.save()
users = authenticate(username=username, password=password)
if users is not None:
login(request,users)
return HttpResponseRedirect('/profile-settings/')
messages.success(request, "This number is registered please try other number or reset your password")
return HttpResponseRedirect('/register/')
In Django default user authentication is integrated through Username and Password. In my project profile page, I have an option to change Username. So, it is necessary to change my authentication system in back end and front end with email and password.
Using authentication backend i can change default authentication system through email and password in admin. Here is the code -
class EmailBackend(object):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
try:
user = UserModel.objects.get(email=username)
except UserModel.DoesNotExist:
return None
else:
if getattr(user, 'is_active', False) and user.check_password(password):
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
In settings.py -
AUTHENTICATION_BACKENDS = (
'apps.account.email-auth.EmailBackend',
)
I was wondering how could i do the authentication through in front end. Already, I prepared front login page through email and password.
But see form.errors and predict must be missing any front authentication like AUTHENTICATION_BACKENDS
Thank you very much for your help!
Actually answer is within the method -
def authenticate(self, username=None, password=None, **kwargs):
In front-end, naming the user input with email wouldn't be passed within the method then form errors show up with don't match credentials. So, simply taking input as username solves the trick.
There is a package django-allauth. It handles the authentication.
It allows using 'email' and 'password' or 'username' and 'password' for authentication. It includes forms and everything else needed.
Django-cookiecutter project template uses this package to handle authentication, so you can look there and use it as a sample.
I'm trying to use a custom backend for user authorization with django-nonrel (email adrresses instead of usernames, nothing fancy), and it's just not working. All calls to authenticate() return None. Here is my backend:
from django.contrib.auth.models import User, check_password
class EmailAuthBackend(object):
"""
Email Authentication Backend
Allows a user to sign in using an email/password pair rather than
a username/password pair.
"""
supports_anonymous_user = False
supports_object_permissions = True
def authenticate(self, email=None, password=None):
""" Authenticate a user based on email address as the user name. """
try:
user = User.objects.get(email=email)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, user_id):
""" Get a User object from the user_id. """
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
And the view (I'm trying to log a user in immediately after they have signed up). new_user is always None:
def create_new_user(request):
if request.method == 'POST':
data = request.POST.copy()
data['username'] = ''.join([choice(letters) for i in xrange(30)])
data['password'] = data['password1']
form = CustomUserCreationForm(data)
if form.is_valid():
user = form.save(commit=False)
# user must be active for login to work
user.is_active = True
user.save() #not sure if this is actually saving
new_user = authenticate(username=data['username'],\
password=data['password'])
if new_user is None:
messages.error(request,"God damn it.")
login(request, new_user)
messages.info(request, "Thanks for registering! You are\
now logged in.")
return render_to_response('invoicer/welcome.html',
{'user':new_user})
else:
messages.error(request, form._errors)
return HttpResponseRedirect('//')
Can anyone give me some insights as to why my call to authenticate() isn't working?
Edit: Also, When deployed, my signup form is definitely creating users which can be seen in the data viewer on appengine.google.com
Turns out all I needed to do was change
authenticate(username=email
in the view to:
authenticate(email=email
My backend wasn't being sent an email so it defaulted to none. Shame on me. However, as I'm using the standard django login form, it will pass a named username and password to my backend, so I have to be able to handle both a username (which is actually the user's email address) and email as named keywords.
For now, I'm just doing it like this in my backend:
def authenticate(self, username=None, email=None, password=None):
""" Authenticate a user based on email address as the user name. """
if username:
might_be_email = username
elif email:
might_be_email = email
An try to find the user by might_be_email.