1

I have a following question regarding Django authentication middleware:

class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
            "The Django authentication middleware requires session middleware "
            "to be installed. Edit your MIDDLEWARE setting to insert "
            "'django.contrib.sessions.middleware.SessionMiddleware' before "
            "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        )
        request.user = SimpleLazyObject(lambda: get_user(request))

As you can see here middleware calls method get_user from backend (in my case simple_jwt) and puts this method in a SimpleLazyObject in order to evaluate later.

def get_user(self, validated_token):
    """
    Attempts to find and return a user using the given validated token.
    """
    try:
        user_id = validated_token[api_settings.USER_ID_CLAIM]
    except KeyError:
        raise InvalidToken(_('Token contained no recognizable user identification'))

    try:
        user = User.objects.get(**{api_settings.USER_ID_FIELD: user_id})
    except User.DoesNotExist:
        raise AuthenticationFailed(_('User not found'), code='user_not_found')

    if not user.is_active:
        raise AuthenticationFailed(_('User is inactive'), code='user_inactive')

    return user

What I want to do is to keep request.user = SimpleLazyObject(lambda: get_user(request)) in order to provide user instance for apps that uses it but for my custom apps I want to add something like

pseudocode

request.user_id = user_id from  user (user_id = validated_token[api_settings.USER_ID_CLAIM])

in order to not query database each and every request for user object in case I need only user_id which I already have directly in get_user method in backend.

Question – how to pass user_id from get_user() to AuthenticationMiddleware.process_request() and set request.user_id attribute to request without evaluating SimpleLazyObject?

Strangelly i can't assign attributes to request in class JWTAuthentication(authentication.BaseAuthentication): where get_user() is belong

Thank you.

Internal Server Error: /auth/users/me/
Traceback (most recent call last):
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 330, in thread_handler
    raise exc_info[1]
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\core\handlers\exception.py", line 38, in inner
    response = await get_response(request)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\utils\deprecation.py", line 126, in __acall__
    response = await sync_to_async(
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 296, in __call__
    ret = await asyncio.wait_for(future, timeout=None)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\asyncio\tasks.py", line 440, in wait_for
    return await fut
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\current_thread_executor.py", line 23, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\asgiref\sync.py", line 334, in thread_handler
    return func(*args, **kwargs)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\auth\middleware.py", line 26, in process_request
    request.user_id = _get_user_session_key(request)
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\auth\__init__.py", line 58, in _get_user_session_key
    return get_user_model()._meta.pk.to_python(request.session[SESSION_KEY])
  File "C:\ProgramData\Miniconda3\envs\entropy\lib\site-packages\django\contrib\sessions\backends\base.py", line 65, in __getitem__
    return self._session[key]
KeyError: '_auth_user_id'
Aleksei Khatkevich
  • 1,923
  • 2
  • 10
  • 27

1 Answers1

1

You already have the user id available. It's decoded from the session inside auth.get_user() and you can just copy that to your own MiddleWare:

from django.contrib.auth import _get_user_session_key

request.user_id = _get_user_session_key(request)

This is a Django private API, not sure why they kept it private. But you can also just copy the one liner it implements:

request.user_id = get_user_model()._meta.pk.to_python(
    request.session[SESSION_KEY]
)
  • Thanks for the answer. In first case it throws an exception (traceback in main question block) and in second there are no SESSION_KEY or 'SESSION_KEY' key availible. Alos i use JWT backend so that it might bot be any SESSION_KEY at all – Aleksei Khatkevich Oct 29 '20 at 18:49
  • 1
    If you don't use session authentication, then this middleware does nothing and you need to roll your own or if your JWT authentication has it available look at theirs to see where they set request.user. –  Oct 29 '20 at 19:34
  • Thats the answer. For some reson i have convinced myself that middleware has something to do with it in case of JWT auth. But in fact it does not. Thanks for the answer – Aleksei Khatkevich Oct 30 '20 at 09:23