Fixed #31920 -- Made AuthenticationMiddleware add request.auser().

This commit is contained in:
Jon Janzen 2023-02-13 18:24:35 -05:00 committed by Mariusz Felisiak
parent e83a88566a
commit e846c5e724
5 changed files with 50 additions and 0 deletions

View File

@ -1,3 +1,7 @@
from functools import partial
from asgiref.sync import sync_to_async
from django.contrib import auth from django.contrib import auth
from django.contrib.auth import load_backend from django.contrib.auth import load_backend
from django.contrib.auth.backends import RemoteUserBackend from django.contrib.auth.backends import RemoteUserBackend
@ -12,6 +16,12 @@ def get_user(request):
return request._cached_user return request._cached_user
async def auser(request):
if not hasattr(request, "_acached_user"):
request._acached_user = await sync_to_async(auth.get_user)(request)
return request._acached_user
class AuthenticationMiddleware(MiddlewareMixin): class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
if not hasattr(request, "session"): if not hasattr(request, "session"):
@ -23,6 +33,7 @@ class AuthenticationMiddleware(MiddlewareMixin):
"'django.contrib.auth.middleware.AuthenticationMiddleware'." "'django.contrib.auth.middleware.AuthenticationMiddleware'."
) )
request.user = SimpleLazyObject(lambda: get_user(request)) request.user = SimpleLazyObject(lambda: get_user(request))
request.auser = partial(auser, request)
class RemoteUserMiddleware(MiddlewareMixin): class RemoteUserMiddleware(MiddlewareMixin):

View File

@ -281,9 +281,23 @@ middleware class is listed in :setting:`MIDDLEWARE`.
else: else:
... # Do something for anonymous users. ... # Do something for anonymous users.
The :meth:`auser` method does the same thing but can be used from async
contexts.
Methods Methods
------- -------
.. method:: HttpRequest.auser()
.. versionadded:: 5.0
From the :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`:
Coroutine. Returns an instance of :setting:`AUTH_USER_MODEL` representing
the currently logged-in user. If the user isn't currently logged in,
``auser`` will return an instance of
:class:`~django.contrib.auth.models.AnonymousUser`. This is similar to the
:attr:`user` attribute but it works in async contexts.
.. method:: HttpRequest.get_host() .. method:: HttpRequest.get_host()
Returns the originating host of the request using information from the Returns the originating host of the request using information from the

View File

@ -65,6 +65,9 @@ Minor features
* The default iteration count for the PBKDF2 password hasher is increased from * The default iteration count for the PBKDF2 password hasher is increased from
600,000 to 720,000. 600,000 to 720,000.
* ``AuthenticationMiddleware`` now adds an :meth:`.HttpRequest.auser`
asynchronous method that returns the currently logged-in user.
:mod:`django.contrib.contenttypes` :mod:`django.contrib.contenttypes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -368,6 +368,7 @@ Django uses :doc:`sessions </topics/http/sessions>` and middleware to hook the
authentication system into :class:`request objects <django.http.HttpRequest>`. authentication system into :class:`request objects <django.http.HttpRequest>`.
These provide a :attr:`request.user <django.http.HttpRequest.user>` attribute These provide a :attr:`request.user <django.http.HttpRequest.user>` attribute
and a :meth:`request.auser <django.http.HttpRequest.auser>` async method
on every request which represents the current user. If the current user has not on every request which represents the current user. If the current user has not
logged in, this attribute will be set to an instance logged in, this attribute will be set to an instance
of :class:`~django.contrib.auth.models.AnonymousUser`, otherwise it will be an of :class:`~django.contrib.auth.models.AnonymousUser`, otherwise it will be an
@ -383,6 +384,20 @@ You can tell them apart with
# Do something for anonymous users. # Do something for anonymous users.
... ...
Or in an asynchronous view::
user = await request.auser()
if user.is_authenticated:
# Do something for authenticated users.
...
else:
# Do something for anonymous users.
...
.. versionchanged:: 5.0
The :meth:`.HttpRequest.auser` method was added.
.. _how-to-log-a-user-in: .. _how-to-log-a-user-in:
How to log a user in How to log a user in

View File

@ -43,3 +43,10 @@ class TestAuthenticationMiddleware(TestCase):
) )
with self.assertRaisesMessage(ImproperlyConfigured, msg): with self.assertRaisesMessage(ImproperlyConfigured, msg):
self.middleware(HttpRequest()) self.middleware(HttpRequest())
async def test_auser(self):
self.middleware(self.request)
auser = await self.request.auser()
self.assertEqual(auser, self.user)
auser_second = await self.request.auser()
self.assertIs(auser, auser_second)