0

I am quite new to Django and came across this error. When ever I input a url directly ( '/accounts/admin2@outlook.com/'), django shows the user the view which only logged in users can see. I am using LoginRequiredMixin but it is not helping.

My view file is : `

from django.shortcuts import render,redirect
from django.views.generic import View
from .forms import UserCreationForm,SignInForm
from django.contrib.auth import login,logout,get_backends,authenticate
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.utils.decorators import method_decorator
from .backend import ClientAuthBackend
from .models import MyUser

class UserHomeView(LoginRequiredMixin,View):

    def get(self,request,email):
        print(request.user.is_authenticated())
        return render(request,'user_home_view.html',{'title':'Home','user':MyUser.objects.get(email=email)})

class SignOutView(View):

    def get(self,request):
        logout(request)
        return redirect(to='/accounts/signin/')

class SignInView(View):

    def get(self,request):
        return render(request,'log_in.html',{'title':'Sign In','form':SignInForm()})

    def post(self,request):
        form = SignInForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            password = form.cleaned_data['password']
            user = authenticate(username=email,password=password)
            if user is not None:
                login(request,user)
                return redirect(to='/accounts/' + str(email) + '/')
            else:
                form.add_error(None,"Couldn't authenticate your credentials !")
                return render(request,'log_in.html',{'title':'Sign In','form':form})
        else:
            return render(request, 'log_in.html', {'title': 'Sign In', 'form': form})


class SignUpView(View):

    def get(self,request):
        return render(request,'sign_up.html',{'title':'Sign Up','form':UserCreationForm()})

    def post(self,request):
        form = UserCreationForm(request.POST)
        try:
            if form.is_valid():
                user = MyUser.objects.create_user(email=form.cleaned_data['email'],date_of_birth=
                form.cleaned_data['date_of_birth'],first_name=form.cleaned_data['first_name'],last_name=
                form.cleaned_data['last_name'],password=form.clean_password2())
                return redirect(to='/accounts/signin')
            else:
                return render(request,'sign_up.html',{'title':'Sign Up','form':form})
        except ValueError:
            form.add_error(None,"Passwords don't match !!!")
            return render(request, 'sign_up.html', {'title': 'Sign Up', 'form': form})

`

And that print statement in userhomeview also returns True each time a not logged in user accesses the url directly. My url file is : `

from django.conf.urls import url,include
from django.contrib import admin
from .views import SignUpView,SignInView,SignOutView,UserHomeView

urlpatterns = [
    url(r'^signup/$',SignUpView.as_view()),
    url(r'^signin/$',SignInView.as_view()),
    url(r'^signout/$',SignOutView.as_view()),
    url(r'^(?P<email>[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)/',UserHomeView.as_view()),
]

`

My settings file is : `

"""
Django settings for django_3 project.

Generated by 'django-admin startproject' using Django 1.9.8.

For more information on this file, see
https://docs.djangoproject.com/en/1.9/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.9/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'ac=6)v&jf(90%!op*$ttf29+qw_51n+(5#(jas&f&*(!=q310u'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

STATIC_URL = '/static/'
STATIC_ROOT = '/Users/waqarahmed/Desktop/Python Projects/learning_django/django_3/assets'

STATICFILES_DIRS = (
    os.path.join(
        BASE_DIR,'static',
    ),
)

AUTH_USER_MODEL = 'users.MyUser'
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend','users.backend.ClientAuthBackend')

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users',
]

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'django_3.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'django_3.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/

STATIC_URL = '/static/'

My custom backend file is :

from .models import MyUser
from django.contrib.auth.backends import ModelBackend


class ClientAuthBackend(ModelBackend):

    def authenticate(self,username=None,password=None):
        try:
            user = MyUser.objects.get(email=username)
            if user.check_password(password):
                return user
            else:
                return None
        except MyUser.DoesNotExist:
            return None

    def get_user(self,email):
        try:
            user = MyUser.objects.get(email=email)
            return user
        except MyUser.DoesNotExist:
            return None

`

And my model file is : `

from django.db import models
from django.contrib.auth.models import (
    BaseUserManager,AbstractBaseUser
)
import time
from django.utils.dateparse import parse_date


class MyUserManager(BaseUserManager):
    def create_user(self, email, date_of_birth, first_name, last_name, password=None):

        if not email:
            raise ValueError('User must have an email id !')
        email = str(email).lower()
        date_of_birth = str(date_of_birth)
        user = self.model(
            email = self.normalize_email(email=email),
            date_of_birth = parse_date(date_of_birth),
            first_name = first_name,
            last_name = last_name,
            join_date = time.strftime('%Y-%m-%d'),
        )
        user.set_password(password)
        user.save()

        return user

    def create_superuser(self, email, date_of_birth, first_name, last_name, password=None):

        if not email:
            raise ValueError('User must have an email id !')

        user = self.model(
            email = self.normalize_email(email=email),
            date_of_birth = date_of_birth,
            first_name = first_name,
            last_name = last_name,
            join_date = time.strftime('%Y-%m-%d'),
        )
        user.is_admin = True
        user.set_password(password)
        user.save()

        return user

class MyUser(AbstractBaseUser):

    email = models.EmailField(verbose_name='email address',max_length=255,unique=True)
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    join_date = models.DateField(auto_now_add=True)
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    objects = MyUserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name','last_name','date_of_birth']

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

    def __str__(self):
        return self.email

    def has_perm(self, perm, obj=None):
        return True

    def has_module_perms(self, app_label):
        return True

    @property
    def is_staff(self):
        return self.is_admin

`

Waqar Joyia
  • 17
  • 1
  • 6
  • My django is rusty but I think [decorating class views](https://docs.djangoproject.com/en/1.10/topics/class-based-views/intro/#decorating-class-based-views) in the docs is what you need to read...eg: it doesn't look like you're either using `@method_decorator` or wrapping the route in your views. – Jon Clements Aug 13 '16 at 22:11
  • Jon I have tried that too and I have also tried the method decorator. But they raise an exception and it was working before but when it was working it was letting users log in who weren't even logged in and their request.user.is_aurhenticated was also returning true which should not be happening – Waqar Joyia Aug 13 '16 at 22:15
  • Jon is correct, you need to use `@method_decorator` or wrap `UserHomeView.as_view()` in your `urls.py`. You need to fix this issue before you can debug the other issues. – knbk Aug 13 '16 at 22:59
  • How are you checking whether a user is logged in or not? – knbk Aug 14 '16 at 10:03
  • I have used the LoginRequiredMixin to ensure that only a logged in user can access the UserHomeView get function – Waqar Joyia Aug 14 '16 at 10:04
  • You said that, but you're also saying it doesn't prevent unauthenticated users from seeing the page. How do you determine (besides the mixin) that the user is not authenticated and shouldn't be able to see the page? – knbk Aug 14 '16 at 10:06
  • I type a url directly without logging that user in, for example there's a user who's email id is 'admin2@outlook.com' , so I type the url directly '/accounts/admin2@outlook.com' and it shows the userhomeveiw whereas it should direct it to the sign in page as the user is not logged in. I didn't log in the user first. – Waqar Joyia Aug 14 '16 at 10:08
  • Note that when using the `LoginRequiredMixin`, _any_ logged in user can view the page. You're most likely logged in with a different account. – knbk Aug 14 '16 at 10:33
  • knbk firstly I haven't logged any user in and I am directly accessing that url and secondly when I get this first problem solved should I implement login_required decorator to ensure that only the current logged in user can see his homepage ? – Waqar Joyia Aug 14 '16 at 10:37
  • I was just seeing the source code for LoginRequiredMixin ( https://github.com/django/django/blob/master/django/contrib/auth/mixins.py ) and I can't think of any reason why request.user.is_authenticated would return true if I haven't logged in that user first – Waqar Joyia Aug 14 '16 at 10:38
  • This might be a stupid question, but did you restart your server? – knbk Aug 14 '16 at 11:08
  • Many many many many times .... – Waqar Joyia Aug 14 '16 at 11:09
  • knbk this is the code(https://github.com/django/django/blob/master/django/contrib/auth/__init__.py) for login and logout in django auth and I can't see where they are changing the value of user.is_authenticated to true or false. And in the model (https://github.com/django/django/blob/master/django/contrib/auth/base_user.py) is_authenticated always returns true, so why do they check is_authenticated in login_required decorators if they are not even changing the value of is_authenticated ? – Waqar Joyia Aug 14 '16 at 11:13
  • `request.user` is set to either an `AnonymousUser` instance (which has `user.is_authenticated() == False`) or a `User` instance (with `user.is_authenticated() == True`). When you're logged in, the user is saved in the session, and the `AuthenticationMiddleware` sets `request.user` to the logged in user. – knbk Aug 14 '16 at 11:18
  • Thank you so much for looking into this, this was helpful :) In my case here, that user is an anonymous User as he isn't logged in yet ? So it shouldn't allow access ? – Waqar Joyia Aug 14 '16 at 11:21
  • You can check that by printing `type(request.user)`. Btw, what's the output of `print(request.user)`? – knbk Aug 14 '16 at 11:26
  • > **type(request.user) **: **request.user** : admin2@outlook.com [14/Aug/2016 11:28:00] "GET /accounts/admin2@outlook.com/ HTTP/1.1" 200 1030 > type(request.user) : request.user : admin2@outlook.com – Waqar Joyia Aug 14 '16 at 11:28
  • for request.user it shows 'admin2@outlook.com' and for type(request.user) it shows '' – Waqar Joyia Aug 14 '16 at 11:30
  • That means you are logged in as `admin2@outlook.com`. Try logging out through your logout view, or deleting your cookies if that doesn't work. (I forgot that `request.user` was a lazy object, so `type(request.user)` is rather unhelpful.) – knbk Aug 14 '16 at 11:31
  • Just did that and even after signing out it gives access to homepage and for any user it does that. I have deleted the cookies and it still does that. But if I open this on another browser then it doesn't allow another user to login. But for the current browser it allows **any** user to log in – Waqar Joyia Aug 14 '16 at 11:38
  • In another browser, if I log in a user once, each user can access their homepage without logging in -- don't know what's going on – Waqar Joyia Aug 14 '16 at 11:40

1 Answers1

0

Please correct following things first.

  • Whenever you are using class based view you must use request object via self.
  • Check auth use with the followingself.request.user.is_authenticated()(It will return the what request does have)
  • If you want to use an automated way to check if a request is from an authenticated user you must use following middelwares django.contrib.auth.middleware.AuthenticationMiddleware django.contrib.auth.middleware.RemoteUserMiddleware(add thes two in settings installed_apps) with following decorator from django.contrib.auth.decorators import login_required. Add @login_required above the view.
Tahir Fazal
  • 313
  • 2
  • 6