DRF Middleware proposal #7770
Replies: 4 comments 7 replies
-
So, two years has passed and still no progress? |
Beta Was this translation helpful? Give feedback.
-
I would love to see some examples |
Beta Was this translation helpful? Give feedback.
-
I'm facing this problem as well. The thing is here the from django.http import HttpRequest # Django request
from rest_framework.request import Request # DRF request Mostly, the django can't aware of the existence of DRF request, IMO, this is one of the trade-offs for extending django. So, if I have to do something after the user or the owner of the request is authenticated in DRF Of course we can get the user of requests in django middlewares like how # Ref: https://github.com/django/django/blob/stable/4.2.x/django/contrib/auth/middleware.py#L15-L25
from django.contrib import auth
from django.utils.functional import SimpleLazyObject
def get_user(request):
if not hasattr(request, "_cached_user"):
request._cached_user = auth.get_user(request)
return request._cached_user
class AuthenticationMiddleware(MiddlewareMixin):
def process_request(self, request):
if not hasattr(request, "session"):
raise ImproperlyConfigured(
"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)) by implementing or using the django authentication backends e.g. # Ref: https://github.com/django/django/blob/stable/4.2.x/django/contrib/auth/backends.py#L159-L164
class ModelBackend(BaseBackend):
"""
Authenticates against settings.AUTH_USER_MODEL.
"""
# (...)
def get_user(self, user_id):
try:
user = UserModel._default_manager.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None then, implement a DRF authentication class which will access the django # Ref: https://github.com/encode/django-rest-framework/blob/3.14.0/rest_framework/authentication.py#L112-L133
class SessionAuthentication(BaseAuthentication):
"""
Use Django's session framework for authentication.
"""
def authenticate(self, request):
"""
Returns a `User` if the request session currently has a logged in user.
Otherwise returns `None`.
"""
# Get the session-based user from the underlying HttpRequest object
user = getattr(request._request, 'user', None)
# Unauthenticated, CSRF validation not required
if not user or not user.is_active:
return None
self.enforce_csrf(request)
# CSRF passed with authenticated user
return (user, None) You can see DRF get the Although we can post-process the requests of DRF after DRF authentication flow by customizing the authentication classes, but we still can't post-process the responses of DRF since the authentication classes will be used once only when the So I think if we can have the DRF middleware mechanism that can play like Django middleware, it'll definitely give us more flexibility. BTW, if you can read Chinese, here is my two cents on Django & DRF authentication, also, welcome to have a discussion if you're suffering from the same thing. |
Beta Was this translation helpful? Give feedback.
-
+1 to this idea, I am running into the same issue where I would like to do language activation at the middleware level where the logic is determined on the user properties. Hacking authentication out from the DRF implementation (I am using token authentication) works but incurs an additional DB query cost for the reasons detailed above where the request.user is not shared between the django request and the DRF.request model if it is already instantiated in a middleware. |
Beta Was this translation helpful? Give feedback.
-
Problem
There is a well-known problem described in https://stackoverflow.com/questions/26240832/django-and-middleware-which-uses-request-user-is-always-anonymous. In a nutshell, you can't get
request.user
in any of the django middlewares. This is a really important missing feature, as I would like to perform some actions for all of myAPIViews
(and not only them).For example, I want to:
Hack
Right now, the best solution I have is to inherit from my authentication class and override
authenticate
method by adding there some custom logic. Also, it doesn't really work for handling responses.Idea
I think would be nice to have some kind of DRF Middleware and then Authentication, Permissions and Throttling implemented in this way. Then a user might add as many as they want custom middlewares. It is also will be better aligned with django design.
The idea is super-raw, so dismiss it by any chance, if you have something better. However, the problem is real, so let's use this issue to kick off the discussion and maybe we will come up with something reasonable. Thanks!
Beta Was this translation helpful? Give feedback.
All reactions