I am using custom authentication with custom user model.
When user authenticates it redirects to the home page, as needed, but the user does not get authenticated.
And when I check in a template {{user.is_authenticated}} it says False.
How to fix that?
Here is my backend file for custom authentication:
from contracts.models import User
from django.contrib.auth.hashers import check_password
class AuthBackend:
def authenticate(self, email=None, password=None):
try:
user = User.objects.get(email=email)
if not check_password(password, user.password):
return None
except User.DoesNotExist:
return None
return user
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
my view:
class LoginView(View):
form_class = LoginForm
template_name = 'login.html'
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user = authenticate(email=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('/')
return render(request, self.template_name, {'form': form})
Added to my setting file:
AUTHENTICATION_BACKENDS = ['contracts.auth.backend.AuthBackend']
AUTH_USER_MODEL = 'contracts.User'
Django version is 2.0.4
I fixed it when I changed my login import:
from django.contrib.auth.views import login
to:
from django.contrib.auth import login
Related
So I have this code. However, although I am able to login correctly with sessionid set, the redirected view still indicates request.user.is_authenticated is False. Any assistance is greatly appreciated.
class TeacherLoginView(SuccessMessageMixin, TemplateView):
form_class = TeacherLoginForm
template_name = 'accounts/teacher-login.html'
success_message = 'Logged in Successfully!'
error_message = 'Staff ID or Password incorrect!'
def get(self, request):
form = self.form_class()
message = ''
return render(request, self.template_name, context={'form': form, 'message': message})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = TeacherBackend.authenticate(self, username=form.cleaned_data['staff_id'],
password=form.cleaned_data['password'],
)
if user is not None:
login(request, user, backend='accounts.backends.backends.TeacherBackend')
return redirect('accounts:home')
else:
messages.error(self.request, self.error_message)
return render(request, self.template_name, context={'form': form})
Realised the issue was in the custom auth backend I had coded. I needed to add the get_user method. thanks to this answer too Answer 1, Answer 2
def get_user(self, user_id):
try:
return CustomUser.objects.get(pk=user_id)
except CustomUser.DoesNotExist:
return None
So I'm starting to learn Django authentication.
from django.contrib.auth import login as log_in
def login(request):
...
if request.method == "POST":
form = UserLoginForm(request.POST)
if form.is_valid():
user = User.objects.filter(email=form.cleaned_data["email"])
if user.exists():
user = user.first()
if check_password(
form.cleaned_data["password"], user.password
):
log_in(request,user)
return redirect("/main/")
else:
messages.warning(request, "email/password are incorrect")
else:
messages.warning(request, "User not found")
...
and I'm trying to access the request.user in another view like this:
if request.user.is_authenticated:
#do somthing
but while debugging I found that after the first code log_in() statement the request.user is authenticated, but in the seconed code it's not.
You have to set the authentication backend:
from django.conf import settings
# ...
user.backend = settings.AUTHENTICATION_BACKENDS[0]
log_in(request, user)
I found the problem,
The problem is that I'm using a custom user model with an email attribute instead of a username so I had to build a new Backend to use with my custom model, then added it to the AUTHENTICATION_BACKENDS in the settings.py file.
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.hashers import check_password
from .models import User
class NewBackend(ModelBackend):
def authenticate(self, request, email, password) -> User:
try:
user: User = User.objects.get(email=email)
if user.check_password(password):
return user
else:
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
and in views.py
def login(request: HttpRequest):
if request.user.is_authenticated:
return redirect("/main/")
if request.method == "POST":
form = UserLoginForm(request.POST)
if form.is_valid():
umail=form.cleaned_data['email']
upasswd=form.cleaned_data['password']
user = authenticate(request=request,email=umail,password=upasswd)
if user is not None:
log_in(request,user)
return redirect("/main/")
else:
messages.warning(request, "email/password are incorrect")
form = UserLoginForm()
context = {"title": "Login", "form": form}
return render(request, "login.html", context)
settings.py:
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'login_signup.backend.NewBackend',
]
I initially used to login using email and password but now want to change it in such a way that we can login using either mobile no or email address and password.I am not able to understand what parts to change in my code as I do not want to delete already existing user and data.
forms.py
from django.contrib.auth.models import User
from django import forms
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'password']
views.py
class UserFormView(View):
form_class = UserForm
template_name = 'main/registration_form.html'
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
# cleaned (normalized) data
email = form.cleaned_data['email']
password = form.cleaned_data['password']
user.username = email
user.set_password(password)
user.save()
# return user objects if credentials are correct
user = authenticate(username=email, password=password)
if user is not None:
if user.is_active:
login(request, user)
# request.user.username display their username
return redirect('main:register2')
return render(request, self.template_name, {'form': form})
class LoginForm(View):
form_class = UserForm
template_name = 'main/login_form.html'
def get(self, request):
form = self.form_class(None)
if error:
return render(request, self.template_name, {'form': form},
{'error': error})
else:
return render(request, self.template_name, {'form': form})
def post(self, request):
email = request.POST.get('email', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=email, password=password)
if user is not None and user.is_active:
# Correct password, and the user is marked "active"
auth.login(request, user)
# Redirect to a success page.
return HttpResponseRedirect("/main/home/")
else:
# Show an error page
error = True
return HttpResponseRedirect("/main/", {'error': error})
Please answer considering the fact that I am new to Django. Thanks in advance :)
In the post method of your view, identify what has the user given you. If it's an email, feed the Django's authenticate() method with the email. If not, then assume it's a phone number (you may also run additional validations in there) and use this in the authentication procedure.
Another approach would be to create a custom authenticate() method, which would look like this:
from django.contrib.auth.backends import ModelBackend
class MobilePhoneOrEmailModelBackend(ModelBackend):
def authenticate(self, username=None, password=None):
# the username could be either one of the two
if '#' in username:
kwargs = {'email': username}
else:
kwargs = {'mobile_phone': username}
try:
user = User.objects.get(**kwargs)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
def get_user(self, username):
try:
return User.objects.get(pk=username)
except User.DoesNotExist:
return None
Let me know if this worked out well for you.
Credits to user user3282276 in this thread as well: Log in user using either email address or username in Django
I am learning class based views in Django 1.8, and wondering if anyone could help me here. I have created a function based login and logout views as you can see below:
LOGIN
def Login(request):
if request.method == "POST":
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)
return HttpResponseRedirect('/form')
else:
return HttpResponse("Inactive user.")
else:
return HttpResponseRedirect(settings.LOGIN_URL)
return render(request, "index.html")
LOGOUT
def Logout(request):
logout(request)
return HttpResponseRedirect(settings.LOGIN_URL)
Could anyone help me to convert these views into Class Based Views in Django? I am pretty new to this stuff, and couldn't understand properly how exactly they are working. Will appreciate any help!
Go through the documentation https://docs.djangoproject.com/en/1.8/topics/class-based-views/intro/#using-class-based-views
from django.views.generic import View
class LoginView(View):
def post(self, 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)
return HttpResponseRedirect('/form')
else:
return HttpResponse("Inactive user.")
else:
return HttpResponseRedirect(settings.LOGIN_URL)
return render(request, "index.html")
class LogoutView(View):
def get(self, request):
logout(request)
return HttpResponseRedirect(settings.LOGIN_URL)
I have a login_page function and in this function the authenticate() function returns a user object only if it is a superuser. For normal user, it returns None. Which is not as the documentation says.
def login_page(request):
if request.user.is_authenticated(): # if user is already logged in
return HttpResponseRedirect('/') # SHOULD BE DASHBOARD
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
seo_specialist = authenticate(username=username, password=password) #returns None
if seo_specialist is not None:
login(request, seo_specialist)
return HttpResponseRedirect('/') # SHOULD BE DASHBOARD
else:
return render(request, 'login.html', {'form': form})
else:
return render(request, 'login.html', {'form': form})
else:
form = LoginForm()
context = {'form': form}
return render(request, 'login.html', context)
Is there anything wrong with my code?
Try this:
def login_page(request):
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
seo_specialist = authenticate(username=username, password=password)
if seo_specialist is not None:
return HttpResponse("Signed in")
else:
return HttpResponse("Not signed in")
else:
# takes you to sign in form.
Basically replace is_valid and cleaned_data with request.POST and then authenticate. Also make sure you have
from django.contrib.auth import authenticate
at the top of your views.
This is from django documentation. You seem to not have passed the request in ...authenticate(request, user...)
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(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...