I have a custom authentication backend that should authenticate tutors as they login. The issue is that the authentication backend returns a user object with correct credentials, but the @login_required decorator receives None for request.user.is_authenticated. So the loop goes from login to login endlessly. I tried printing the session_key across requests, and it is the same.
FILES
Authentication Backend
class TutorAuthBackend(ModelBackend):
def authenticate(self, request, username_or_email=None, password=None, **kwargs):
print(f"Attempting to authenticate: {username_or_email}")
try:
validate_email(username_or_email)
is_valid_email_format = True
except ValidationError:
is_valid_email_format = False
auth_type = 'email__iexact' if is_valid_email_format else 'username__iexact'
auth_param = {auth_type: username_or_email}
try:
tutor = Tutor.objects.get(**auth_param)
if tutor.check_password(password):
print(f"Authenticated: {tutor}")
return tutor
except Tutor.DoesNotExist:
pass
return None
def get_user(self, user_id):
"""
Returns the tutor object using the given user_id.
"""
try:
return Tutor.objects.get(pk=user_id)
except Tutor.DoesNotExist:
return None
def tutor_login(request):
if request.method == 'POST':
username_or_email = request.POST.get('username_or_email')
password = request.POST.get('password')
tutor = TutorAuthBackend().authenticate(request, username_or_email=username_or_email, password=password)
if tutor:
login(request, tutor, backend='tutor.backends.TutorAuthBackend')
messages.success(request, "You're Logged In")
if tutor.profile_picture:
print("Profile Picture:", tutor.profile_picture.url)
return redirect('tutor_dashboard', tutor_id=tutor.id)
return redirect('tutor_profile')
else:
tutor_exists = Tutor.objects.filter(username=username_or_email).exists()
if tutor_exists:
messages.error(request, 'Incorrect Password')
else:
messages.error(request, 'User Not Found')
return render(request, 'tutor/tutor_login.html', context={'username_or_email': username_or_email})
else:
return render(request, 'tutor/tutor_login.html')
First, I tried to print out how the view communicates with the authentication backend by printing before and after the backend returns something. The backend returns a valid authenticated user. In the dashboard view, I printed request.user.is_authenticated() and it returns false, I printed the request.user and it returned AnonymousUser. I tried to know if the session was the problem by increasing the SESSION_COOKIE_AGE to 7 days and explicitly specifying the SESSION_ENGINE to django.contrib.sessions.backends.db in settings.py. I have also tried to log the session_key for each user looping the login page, and it appears consistent. I couldn't make helpful meaning from the Django docs too. Thank you in advance for your assistance.
I have resolved the issue. The problem was of naming convention. My custom backend was named
tutor_backends.pyrather thanbackends.py.It seems Django doesn't understand any custom backend that is not exactly namedbackends.py. So even though the logic is correct and the backend authenticates, the authentication does not persist to session hence,@login_requiredwhich checks is a session useris_authenticatedreceives anFalsebeccause auths doesn't persist to session. I hope this helps someone. Unfortunately, I didn't see that spelt out in the docs.