How can I programmatically authenticate a user in Django? - python

How can I log-in the user programmatically in Django? I have the username and password of the User. Is there a method that let's me log him in?

There is no other way than "programmatically". Of course, this is documented.
from django.contrib.auth import authenticate, login
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)

Alsways be careful when programmatically logging users in, you might get the error ´user has no attribute "backend". You have to set the backend too if that has no happened previously. Project that uses this and some sample code:
def splash_register(request):
if request.session.get('beta'):
if request.method=='POST':
userform=MyUserCreationForm(request.POST)
if userform.is_valid():
#username of <30 char is required by Django User model. I'm storing username as a hash of user email
user=userform.save(commit=False)
user.username=hash(user.email)
user.backend='django.contrib.auth.backends.ModelBackend'
user.save()
username=user.username
password=str(userform.cleaned_data['password'])
auth.login(request, user)
request.session['first_visit']=True
return HttpResponseRedirect("/")
else:
userform=MyUserCreationForm(request.POST)
return render_to_response("website/splash_register.html", {'userform':userform}, context_instance=RequestContext(request))
return render_to_response("website/splash_register.html", context_instance=RequestContext(request))
else:
return HttpResponseRedirect('/splash/')

The accepted answer definitely works but, I prefer to use the Django built in auth forms, like django.contrib.auth.forms.AuthenticationForm
Here is a snippet that shows the important part
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
try:
form.clean()
except ValidationError:
# handle error
login(request, form.get_user())
The major difference in this approach is that AuthenticationForm.clean method calls authentication function for you and checks User.is_active for you as well.

Related

Use django PasswordResetView functionality in my own view

I want to use django's default password reset view "PasswordResetView" which let's the user reset his password when he forgets it in a template that already has a view that i built on my own, after looking at the tutorials and the questions i found how to use it only on a different template that is made only for the password reset, but i don't want the user to go to a different page just to change his password when he forgets it, i want to make it in a bootstrap modal in the home page.
here is my home view that i want to add PasswordResetView functionality to it:
def home(request):
user = request.user
signin_form = SigninForm()
signup_form = SignupForm()
if request.method == "POST":
if 'signin_form' in request.POST:
signin_form = SigninForm(request.POST)
if signin_form.is_valid():
email = request.POST['email']
password = request.POST['password']
user = authenticate(email=email, password=password)
if user:
login(request, user)
elif user is None:
messages.error(request, 'ُEmail or password is incorrect')
if 'signup_form' in request.POST:
signup_form = SignupForm(request.POST)
if signup_form.is_valid():
signup_form.save()
full_name = signup_form.cleaned_data.get('full_name')
email = signup_form.cleaned_data.get('email')
raw_password = signup_form.cleaned_data.get('password1')
account = authenticate(email=email, password=raw_password)
login(request, account)
context = {'signin_form': signin_form,'signup_form': signup_form}
return render(request, 'main/home.html', context)
PS: i tried copy pasting the source code of that view (PasswordResetView) from django's source code in my view but i found some errors because it's a class based view, so if you find this the proper way, guide me to do it
or if i can't merge them somehow how to create a custom one
this is what i found in the other answers which lets you use it in a certain template that has only that view (PasswordResetView) which is not what i want:
from django.contrib.auth import views as auth_views
path('password_reset/', auth_views.PasswordResetView.as_view(template_name="myapp/mytemplate.html",form_class=mypasswordresetform),name="reset_password"),
I'll give you a simple approach to having a password reset feature on your django application. Before having any code, let me give a brief exlanation of the process. What you want to do is get a user to input their email, check if there is any user with that email, then if there is one, send an email to that address with a uniquely generated link.
From this link, you should be able to extract the user object which you need to change password. An example would be to use django's signing module. This link will simply need to redirect the user to a template where there is a form with 2 fields i.e. New Password and Verify Password.
Django's generic views come with this functionality out-of-the-box if you are using Django's authentication module, but you aren't forced to use it, but its best to do so.
Here I'll only show you how to collect the email address on the same view as you said you wanted.
def home(request):
# ...your other code
if request.method == 'post':
if 'reset_password' in request.POST:
email = request.POST.get("email", "")
user_qs = User.objects.filter(email=email)
if not user_qs.exists():
# send error message to user here
else:
user = user_qs.get()
# send email with uniquely generated url here.
The other aspects of generating a URL and sending the mail, I believe you can research these separately. But I hope you now have an idea of where and what to search.

Django login() doesn't persist after HttpResponseRedirect

I have custom Django login forms that, since upgrading from Django 1.8 to 2.2, no longer keep user logged in after HttpResponseRedirect. Here's is a generalized sample of the code:
#render_with('users/login.html')
def login_view(request, campaign_id=None):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
password = form.cleaned_data['password']
# Login user
user = authenticate(request, email=email, password=password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/redirect-user/')
I know that login() is working properly because if I use render instead of HttpResponseRedirect, the user is logged in. However, I want to redirect the user to a different view after login. What is the best way to do this?
UPDATE
It appears that the culprit is my custom authenticate backend EmailOrUsernameModelBackend. Any ideas what I am doing wrong?
settings.py
AUTHENTICATION_BACKENDS = (
'social_core.backends.open_id.OpenIdAuth',
'social_core.backends.google.GoogleOpenId',
'social_core.backends.facebook.FacebookOAuth2',
'social_core.backends.google.GoogleOAuth2',
'social_core.backends.linkedin.LinkedinOAuth2',
'users.backends.EmailOrUsernameModelBackend',
'django.contrib.auth.backends.ModelBackend',
)
__init__.py
class EmailOrUsernameModelBackend(object):
supports_object_permissions = False
supports_anonymous_user = False
supports_inactive_user = False
def authenticate(self, request, email=None, password=None):
if '#' in email:
kwargs = {'email': email.lower() }
else:
kwargs = {'username__iexact': email.lower() }
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
Also, if I change the code and logout/login again to test, it works the 1st test and fails on subsequent tests with the same user.
Thanks to #Sayse's suggestion about middleware/backends causing the issue. Removing 'users.backends.EmailOrUsernameModelBackend' fixed the issue in the question above, but consequently broke my login after a new user registers. In order to get both login and registration working, I switched the other of EmailOrUsernameModelBackend and ModelBackend:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'users.backends.EmailOrUsernameModelBackend',
)
Per Django docs:
The order of AUTHENTICATION_BACKENDS matters, so if the same username
and password is valid in multiple backends, Django will stop
processing at the first positive match.
I am still not sure what is wrong with the EmailOrUsernameModelBackend causing it to break my login, but this did fix the issue. If anybody has a better fix for the root cause (ie what is wrong with this backend), I will accept as the best answer.
I had the same problem, but reordering the backends in settings did not help.
login(request, user) can take a third argument, the backend to use, e.g.
backend = `django.contrib.auth.backends.ModelBackend'
login(request, user, backend)
If you remove django.contrib.auth.backends.ModelBackend from settings.AUTHENTICATION_BACKENDS, inside django/contrib/auth/__init__.py -> get_user is:
if backend_path in settings.AUTHENTICATION_BACKENDS:
...
else:
return None
So if you specify the backend, but its not in your settings.AUTHENTICATION_BACKENDS, your user will never authenticate.

Django User Authentication - Can't pass #login_required decorator

So I'm currently trying to implement an already existing application for payment processing via Braintree (https://github.com/Tivix/django-braintree for reference). It seems like all the meat of this application is placed at the /payments-billing/ directory but I can't seem to get into it to check it out. It seems like what's stopping me is a #login_required decorator placed just before the view since whenever I access the directory it sends me back to the defined LOGIN_URL. However I have set up a login feature at the LOGIN_URL that authenticates the user and then sends them to /payments-billing/ but it just redirects back again. Here is my code:
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
# Password verified for user
if user.is_active:
return redirect(self.success_url)
else:
return redirect('/')
else:
return redirect('/')
Clearly the user is being authenticated and is active since it passes both tests when you try it, but it always just sends the user back to the LOGIN_URL rather than /payments-billing/. Anyone know what's the deal here?
The authenticate function doesn't log a user in, it just checks their username/password. You also have to call django.contrib.auth.login() to do the actual logging in. See the example in the documentation.
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
login(request, user)
### Now it should get redirected to /payments-billing/
if user is not None:
# Password verified for user
if user.is_active:
return redirect(self.success_url)
else:
return redirect('/')
else:
return redirect('/')

AuthenticationForm not working

I'm experimenting with Django and I tried to create a login/register application. Here's where I've stuck - I'm able to register users, but then I can't login with them. Here's the code I think is relevant:
views.py
def login(request, template='accounts/sign_in.html'):
if request.user.is_authenticated():
return redirect(reverse('games'))
if request.method == 'POST':
post = request.POST.copy()
if 'password' in post:
post['password'] = make_password(post['password'])
form = AuthenticationForm(data=post)
if form.is_valid():
login(request, form.get_user())
messages.success(
request, "Successfully logged in.", extra_tags='success')
return redirect(reverse('games'))
else:
messages.warning(
request, "Wrong username or password." + request.POST['username'] + " " + request.POST['password'], extra_tags='error')
return redirect(reverse('login'))
return views.login(request, template)
def register(request, template='accounts/sign_up.html'):
if request.user.is_authenticated():
return redirect(reverse('home'))
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
new_user = User(
username=form.cleaned_data['username'],
password=make_password(form.cleaned_data['password1']),
is_active=True,
)
new_user.save()
messages.success(request, "Your account was successfully created.")
return redirect(reverse('games'))
else:
form = RegisterForm()
return render(request, template, {'register_form': form})
When I try to log in with a user I've created (username: qwe, password: qweqweqwe), I get redjrected to login again, but the exact same username and password are printed in the message:
Wrong username or password.qwe qweqweqwe
However, when I try the interactive shell, here's what I get:
>>> User.objects.all()
[<User: admin>, <User: asd>, <User: qwe>]
>>> User.objects.all()[2]
<User: qwe>
>>> User.objects.all()[2].password
u'pbkdf2_sha256$10000$HM2k6uDntJ68$DLqHKcGxtJG7pJC7tbZcm29vB88LEgaw2xroqZEkTFw='
So I have such a user and it's a valid account.
I'm pretty sure you don't need to call make_password in this one:
if 'password' in post:
post['password'] = make_password(post['password'])
form = AuthenticationForm(data=post)
Just pass the normal request.POST to data and the form itself do the encryption and test it against the database. This is the fragment of AuthenticationForm's clean method where it do this:
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = authenticate(username=username,
password=password)
...
You can see the whole definition here.
I suppose your using official make_password function from django.contrib,auth but take a look at the docs closely, normally, user register functions do this automatically so you won't have to do it.
Anyways:
Check the errors form is yielding after is_valid call and change your login code to this:
if request.method == 'POST':
form = AuthenticationForm(data=request.POST)
Hope this helps!
Issue no. 1 - wrong login()
This is probably the problem:
login(request, form.get_user())
You already have a login function and it happens to be a view. I suppose you want to confirm user authentication (form.is_valid() does not do that automatically).
More details are in the documentation of auth module:
How to log a user in
If you have an authenticated user you want to attach to the current
session - this is done with a login() function.
login()
To log a user in, from a view, use login(). It takes an HttpRequest
object and a User object. login() saves the user’s ID in the session,
using Django’s session framework.
Note that any data set during the anonymous session is retained in the
session after a user logs in.
This example shows how you might use both authenticate() and login():
from django.contrib.auth import authenticate, login
def my_view(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(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.
Issue no. 2 - wrong password
As Paulo mentioned, AuthenticationForm already handles password hashing. Please read the official documentation for examples:
Using the Django authentication system: Authentication in Web requests

Django Redirect after Login Error

Im new to Django and I know that to redirect after login I have to set the parameter 'page'. But this only works when the login is successful. How can i do the same thing when some error occurs??
Ps: Im currently also using django-registration with simple backend
I think it's what you are looking for:
# Login
def connection(request):
# Redirect to dashboard if the user is log
if request.user.is_authenticated():
return redirect('YourProject.views.home')
# Control if a POST request has been sent.
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None: #Verify form's content existence
if user.is_active: #Verify validity
login(request, user)
return redirect('/index') #It's ok, so go to index
else:
return redirect('/an_url/') #call the login view
return render(request, 'login.html', locals()) #You can remove local() it is for user's data viewing..

Categories