is_authenticated returns True for logged out user

1.4k views Asked by At

I'm writing a server app using Django, Django REST framework, Django-rest-auth and Django-allauth. I have a method that's used to pass messages between users, and this should only happen when the receiver is logged in.

However, it seems that the user object's is_authenticated() method returns True even though the user has logged out (called rest-auth/logout/, which should in turn call Django's logout). What could cause this? Is there something I've missed here?

Here's the code I have:

class SendMessage(generics.CreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = MessageSerializer

    def perform_create(self, serializer):
        m = self.request.data['msg']
        targetUser = User.objects.get(pk = self.request.data['user'])

        if targetUser.is_authenticated():
            # Send message
        else:
            # Don't send message
3

There are 3 answers

5
Mark Galloway On BEST ANSWER

Unfortunately, the is_authenticated() method always returns true.

 def is_authenticated(self):
    """
    Always return True. This is a way to tell if the user has been
    authenticated in templates.
    """
    return True

It is meant to discern between a User instance and an AnonymousUser instance, which is what the User is set as when they do not pass authentication.

5
Yahya Yahyaoui On

Try fetching all authenticated users, then check if the target user is among them or not:

from django.contrib.auth.models import User
from django.contrib.sessions.models import Session
from django.utils import timezone

def get_all_logged_in_users_ids():
    # Query all non-expired sessions
    # use timezone.now() instead of datetime.now() in latest versions of Django
    sessions = Session.objects.filter(expire_date__gte=timezone.now())
    uid_list = []

    # Build a list of user ids from that query
    for session in sessions:
        data = session.get_decoded()
        uid_list.append(data.get('_auth_user_id', None))
    return uid_list

class SendMessage(generics.CreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = MessageSerializer

    def perform_create(self, serializer):
        m = self.request.data['msg']
        if (self.request.data['user'] in get_all_logged_in_users_ids()):
            # Send message
        else:
            # Don't send message

Reference.

3
Daniel Roseman On

You've misunderstood what is_authenticated is checking.

Remember that the web is a stateless environment. There is no server-level 'logged-in' status: the only record of whether a user is logged in or not is whether the cookie exists on that user's machine.

Since it is always possible for the user to close their browser, or turn of their machine, without notifying the server, there is no reliable way to know whether or not a user is really logged in. The only way you can approach that is to have some kind of repeated Ajax call every few seconds, posting to a view that updates the user's record with the current time. Then you can check that the user did indeed update within the last few seconds. This won't be totally reliable, though.

Alternatively you can look into using some kind of long-polling system to keep a channel open.