[Django]-How can I know where the request.user from in Django View?

2👍

I’m assuming you’re using Django’s built-in authentication system – i.e. you have the django.contrib.auth included in your settings installed apps.

Middlewares get a chance to intercept the request before any of your views receive it.
This request.user attribute is set by Django’s auth middleware, here:

class RemoteUserMiddleware(MiddlewareMixin):
    """
    Middleware for utilizing Web-server-provided authentication.
    If request.user is not authenticated, then this middleware attempts to
    authenticate the username passed in the ``REMOTE_USER`` request header.
    If authentication is successful, the user is automatically logged in to
    persist the user in the session.
    The header used is configurable and defaults to ``REMOTE_USER``.  Subclass
    this class and change the ``header`` attribute if you need to use a
    different header.
    """
    ...
    def process_request(self, request):
        ...
        # We are seeing this user for the first time in this session, attempt
        # to authenticate the user.
        user = auth.authenticate(request, remote_user=username)
        if user:
            # User is valid.  Set request.user and persist user in the session
            # by logging the user in.
            request.user = user
            auth.login(request, user)
👤wim

0👍

In Authentication in web requests we read a very short explanation

Django uses sessions and middleware to hook the authentication system into request objects. These provide a request.user attribute on every request which represents the current user. If the current user has not logged in, this attribute will be set to an instance of AnonymousUser, otherwise it will be an instance of User.

For most that information will suffice. Yet, if one wants to understand better what happens under the hood, let’s try to login a user and see what happens.
To log a user in, from a view, we use login(). For example, if one tests in this system by Creative Tim,

One sends a POST request with the data:

username:test
password:ApS12_ZZs8

If login is successful, login() saves the user’s ID in the session using Django’s session framework, which is entirely, and solely, cookie-based, (by default, Django stores sessions in your database, in a django_session table), and we’ll get back a cookie in the request header

cookie: sessionid=53u40ngk6puzfru3gl7p5zhbx0yrkoo3

enter image description here

So, what is that sessionid we are getting? It’s the session_key in the django_session table. The table looks like the following

enter image description here

   Column        |           Type           | Collation | Nullable | Default
----------------------+--------------------------+---------------+--------------+-------------
session_key   | character varying(40)          |                 | not null |
session_data | text                                         |                 | not null |
expire_date    | timestamp with time zone  |                | not null | 

So, knowing the session_key it’s possible to know the session_data. It’s in session_data that when a user logs in, the user’s ID and the backend that was used for authentication are saved as an encoded dictionary. This allows the same authentication backend to fetch the user’s details on a future request.

Since authentication sources are cached on a per-session basis, if one changes AUTHENTICATION_BACKENDS (one can even create a custom one) one will need to clear out session data to force users to re-authenticate using different methods (Session.objects.all().delete()).

By default, Django only saves to the session database when the session has been modified – that is if any of its dictionary values have been assigned or deleted.

Then, when one calls logout(), the session data for the current request is completely cleaned out. In other words, one still gets a cookie: sessionid=... in the header, except that the session_data linked with that session_key won’t have the _auth_user_id like before.

Which is great but that still doesn’t explain how Django knows the user making the request. Looking back at the beginning of the answer, there’s a quote saying Django uses sessions and middleware to hook the authentication system into request objects.. We’ve covered the sessions, so that must be the part handled by Middleware. One is correct if one assumes that. More specifically, Django’s auth middleware sets the request.user attribute here, as noted by wim, and that’s done essentially by extracting the user and the authentication backend from the session.


Notes:

  • As per the documentation, it’s recommended to call clearsessions on a regular basis to purge expired sessions, for example as a daily cron job.

Leave a comment