Opened 4 hours ago

Closed 4 hours ago

#37042 closed Bug (duplicate)

alogin() does not invalidate _acached_user, causing stale AnonymousUser after async login

Reported by: Dong Huynh Owned by:
Component: contrib.auth Version: 5.2
Severity: Normal Keywords: alogin, async, auser
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

When alogin() is called after request.auser() in the same request, subsequent calls to request.auser() return a stale AnonymousUser because alogin() does not update request._acached_user.

The sync path does not have this problem. login() sets request.user = user, which replaces the SimpleLazyObject entirely, so all subsequent request.user access returns the correct user. But in the async path, request.auser() is a separate callable (partial(auser, request)) that caches its result in request._acached_user. alogin() updates request.user but never touches _acached_user.

Reproduction:

class MyAuthMiddleware:
    async def __acall__(self, request):
        # Step 1: check if already authenticated
        user = await request.auser()  # caches AnonymousUser in _acached_user

        if not user.is_authenticated:
            db_user = await User.objects.aget(email="existing@example.com")
            await alogin(request, db_user)  # updates request.user, NOT _acached_user

        response = await self.get_response(request)  # view runs
        return response

# In the view:
async def my_view(request):
    user = await request.auser()  # returns stale AnonymousUser
    assert user.is_authenticated  # FAILS

Fixed in: Django 6.x, which replaces request.auser with a closure after login:

if hasattr(request, "auser"):
    async def auser():
        return user
    request.auser = auser

Workaround for 5.x, after await alogin(request, user):

request._acached_user = user  # Fixed in Django 6.x (alogin replaces request.auser)

Change History (1)

comment:1 by Sarah Boyce, 4 hours ago

Resolution: duplicate
Status: newclosed

Duplicate of #36540 which (as you said) is now fixed from 6.0

Note: See TracTickets for help on using tickets.
Back to Top