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.py
rather than backends.py
.It seems Django doesn't understand any custom backend that is not exactly named backends.py
.
So even though the logic is correct and the backend authenticates, the authentication does not persist to session hence, @login_required
which checks is a session user is_authenticated
receives an False
beccause auths doesn't persist to session. I hope this helps someone. Unfortunately, I didn't see that spelt out in the docs.