Hi all,

I have this weird problem: request.user is not returning the correct user 
(in certain execution path). I think it is related to lazy evaluation of 
request.user.

=========================================
I will summarize the business logic and the problem:
=========================================

All REST APIs are protected by Basic Authentication (username/password info 
is persisted in Postgres)

// rest_framework/views.py
   def perform_authentication(self, request):
        request.user

In a nutshell, the above "request.user" is acting weird!

Normal path: perform_authentication() is called, and request.user will be 
evaluated, and subsequently request._authenticate() is invoked.

Abnormal path: perform_authentication() is called, and request.user will be 
evaluated, but somehow in request.__getattribute__(), "return 
super(Request, self).__getattribute__(attr)" will magically returns an 
incorrect user object without invoking request.user(). The returned user 
object is pointing to a different user. This user seems be from a different 
REST API invocation prior with return status 500.

It seems somehow a failed REST API call is effecting other REST API 
invocations, and the problem will continue until I restart Django. If there 
is no failed call, there seems to be no problem.

It is difficult to debug this problem with debugger because it is easy to 
accidentally force the evaluation of the request.user, and the problem will 
go away.

I have a workaround in perform_authentication(); there I can add some code 
to force explicit call to request._authenticate() prior to "request.user".

I wonder if others have seen similar problems? 

Is this a known bug? Or I did something wrong?

Is there existing solutions?

Any tips is appreciated.

Thanks in advance.

Steve

==============================
Related sources
==============================

// rest_framework/views.py
   def perform_authentication(self, request):
        """
        Perform authentication on the incoming request.

        Note that if you override this and simply 'pass', then 
authentication
        will instead be performed lazily, the first time either
        `request.user` or `request.auth` is accessed.
        """

        request.user

// rest_framework/request.py
    @property
    def user(self):
        print("***sleung get user***")

        """
        Returns the user associated with the current request, as 
authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            self._authenticate()
        return self._user

// rest_framework/request.py
    def __getattribute__(self, attr):
        """
        If an attribute does not exist on this instance, then we also 
attempt
        to proxy it to the underlying HttpRequest object.
        """
        try:
            return super(Request, self).__getattribute__(attr)

        except AttributeError:
            info = sys.exc_info()
            try:
                return getattr(self._request, attr)
            except AttributeError:
                six.reraise(info[0], info[1], info[2].tb_next)


============================
Below are my configuration details:
============================

Ubuntu 16.04 LTS

Python 3.5.2

Django (1.9.12)

djangorestframework (3.3.3)

-- 
You received this message because you are subscribed to the Google Groups 
"Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to