Search code examples
djangoauthenticationoauthdjango-authentication

django request.user.is_authenticated returns AnonymousUser after a while


I have a problem with Django authentification/Login.

I can log in just fine and I'm able to browse a couple of pages with an authenticated and logged-in user until at some point my request.user.is_authenticated returns False. I then have an AnonymousUser and can't access the user information anymore.

This problem is not present on my localhost server and only happens when I try out my production server. I would say this problem occurs every 50% of requests, which means I have one chance out of two that my user keeps its authentication after a redirect. The login() function on my home page works fine everytime I use it so it means the problem arise during the redirect.

I tried to find the specific step where it goes wrong but I only see that the request's attributes disappear when I redirect to a new page. Suddenly the request has no attributes at all when I try:

for key, value in request.session.items():
    print('{} => {}'.format(key, value))

while one page before it would yield me auth_user_id, auth_user_backend and auth_user_hash.

My setup used to work perfectly until I recently tried to implement a Facebook auth with allauth. I had difficulties to get it running and I suspect this might have caused the present issue. I have since removed every line that was related to the facebook login but I still could not get my production server to run.

Here is my settings.py

AUTH_USER_MODEL = 'custom_user.CustomUser'

INSTALLED_APPS = [
    'django.contrib.sites',
    'django.contrib.admin.apps.SimpleAdminConfig',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'debug_toolbar',
    'custom_user.apps.CustomUserConfig',
    'user_profile',
    'rest_framework',
    'django_email_verification',
]

MIDDLEWARE = [
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'debug_toolbar.middleware.DebugToolbarMiddleware',
]

AUTHENTICATION_BACKENDS = [
 'django.contrib.auth.backends.ModelBackend',
]

LOGIN_REDIRECT_URL = '/'

My login form looks like this:

class UserLoginForm(forms.Form):
    email = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Email or Username', 'size':40}))
    password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder':'Password', 'size':40}))

    def clean(self, *args, **kwargs):
        email = self.cleaned_data.get('email')
        password = self.cleaned_data.get('password')

        if email and password:
            user = authenticate(email=email, password=password)
            if not user:
                ##Maybe the user tried to log in with the email address instead
                try:
                    look_up_user = CustomUser.objects.get(email=email)
                    user = authenticate(email=look_up_user.email, password=password)
                except:
                    raise forms.ValidationError('This user is not recognized')
            if not user.check_password(password):
                raise forms.ValidationError('The Password is incorrect')
            if not user.is_active:
                raise forms.ValidationError('This user is not active')
        return super(UserLoginForm, self).clean(*args, **kwargs)

And here is the login view:

def login_view(request):
    next = request.GET.get('next')
    form = UserLoginForm(request.POST or None)
    if form.is_valid():
        email = form.cleaned_data.get('email')
        password = form.cleaned_data.get('password')
        user = authenticate(email=email, password=password)
        login(request, user)
        if request.user.is_authenticated:
            return redirect('/Market/')
        elif next:
            return redirect(next)
        else:
            return redirect('/')
    context = {
            'form':form,
            "title":"sign-up"
    }
    return render(request, "home.html", context)

Here is the logic of my page once a user is IDed:

def my_view(request):
      if request.user.is_authenticated:
            user = request.user
            ##PAGE LOGIC##
            return render(request, 'path_to.html', context)
      else:
            print("User not authenticated. Redirecting User to login page")
            return redirect('/')

NOTE: My User model is custom made but I have not adapted a Middleware or an authentification_backend to it. Might this be the reason my prod server logs me off? If so why would it work in localhost?

Thank you very much for your help.


Solution

  • Glenn from the pythonanywere.com forum found the origin of the issue.

    I was storing my session in cache but I was not using the memecached backend. Storing my session there caused the issue since any new worker relaying the request would not be able to access the cached session.

    My auth would work fine until a new worker was used and then I would lose my auth.

    The issue was fixed by changing:

    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

    to:

    SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'