使用request.user的Django和中间件总是匿名的

2024-06-06 17:51:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试制作一个中间件,它可以根据子域等为用户修改一些字段。。。

唯一的问题是request.user总是以匿名用户的身份出现在中间件中,但在视图中却是正确的用户。我在设置中保留了django使用的默认身份验证和会话中间件。

这里有一个类似的问题:Django, request.user is always Anonymous User 但并没有过度回答整个问题,因为我没有使用不同的身份验证方法,而且djangos身份验证是在调用自己的中间件之前运行的。

在使用DRF时,是否有方法在中间件中获取request.user?我将在此处显示一些示例代码:

class SampleMiddleware(object):

  def process_view(self, request, view_func, view_args, view_kwargs):
    #This will be AnonymousUser.  I need it to be the actual user making the request.
    print (request.user)    

  def process_response(self, request, response):
    return response

处理请求:

class SampleMiddleware(object):

  def process_request(self, request):
    #This will be AnonymousUser.  I need it to be the actual user making the request.
    print (request.user)    

  def process_response(self, request, response):
    return response

Tags: 中间件the方法用户self身份验证viewresponse
4条回答

基于Daniel Dubovski在上面非常优雅的解决方案,下面是Django 1.11的中间件示例:

from django.utils.functional import SimpleLazyObject
from organization.models import OrganizationMember
from django.core.exceptions import ObjectDoesNotExist


def get_active_member(request):
    try:
        active_member = OrganizationMember.objects.get(user=request.user)
    except (ObjectDoesNotExist, TypeError):
        active_member = None
    return active_member


class OrganizationMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response


    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        request.active_member = SimpleLazyObject(lambda: get_active_member(request))

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.
        return response

今天遇到同样的问题。

TL;DR;

跳过下面的代码示例


说明

事情是DRF有自己的事情流,就在django请求的中间life-cycle

因此,如果正常的中间件流是:

  1. 请求中间件(在开始处理请求之前)
  2. 视图中间件(在调用视图之前)
  3. 模板中间件(渲染前)
  4. 响应中间件(最终响应前)

DRF代码,重写默认的django视图代码,并执行their own code

在上面的链接中,可以看到它们用自己的方法包装原始请求,其中一个方法是DRF身份验证。

因此,回到您的问题,这就是为什么在中间件中使用request.user还为时过早,因为它只在执行查看中间件**之后才获得其值。

我采用的解决方案是让我的中间件设置为LazyObject。 这很有帮助,因为我的代码(实际的DRF ApiVIew)在实际用户已经由DRF's authentication设置时执行。 这个解决方案是proposed here加上一个讨论。

如果DRF有更好的方法来扩展它们的功能,可能会更好,但事实上,这似乎比提供的解决方案要好(从性能和可读性两方面来看)。


代码示例

from django.utils.functional import SimpleLazyObject

def get_actual_value(request):
    if request.user is None:
        return None

    return request.user #here should have value, so any code using request.user will work


class MyCustomMiddleware(object):
    def process_request(self, request):
        request.custom_prop = SimpleLazyObject(lambda: get_actual_value(request))

今天遇到同样的问题。

TL;DR;

跳过下面的代码示例


说明

事情是DRF有自己的事情流,就在django请求的中间life-cycle

因此,如果正常的中间件流是:

  1. 请求中间件(在开始处理请求之前)
  2. 视图中间件(在调用视图之前)
  3. 模板中间件(渲染前)
  4. 响应中间件(最终响应前)

DRF代码,重写默认的django视图代码,并执行their own code

在上面的链接中,您可以看到它们用自己的方法包装原始请求,其中一个方法是DRF身份验证。

因此,回到您的问题,这就是为什么在中间件中使用request.user还为时过早,因为它只在执行查看中间件**之后才获得其值。

我采用的解决方案是让我的中间件设置为LazyObject。 这很有帮助,因为我的代码(实际的DRF ApiVIew)在实际用户已经由DRF's authentication设置时执行。 这个解决方案是proposed here加上一个讨论。

如果DRF有更好的方法来扩展它们的功能,可能会更好,但事实上,这似乎比提供的解决方案要好(从性能和可读性两方面来看)。


代码示例

from django.utils.functional import SimpleLazyObject

def get_actual_value(request):
    if request.user is None:
        return None

    return request.user #here should have value, so any code using request.user will work


class MyCustomMiddleware(object):
    def process_request(self, request):
        request.custom_prop = SimpleLazyObject(lambda: get_actual_value(request))

嘿,伙计们,我通过从请求中获取DRF令牌并将request.user加载到与该模型相关联的用户,解决了这个问题。

我有默认的django身份验证和会话中间件,但DRF似乎是在一个接一个地使用它的令牌身份验证中间件来解析用户(所有请求都是CORS请求,这可能就是原因)。下面是我更新的中间件类:

from re import sub
from rest_framework.authtoken.models import Token
from core.models import OrganizationRole, Organization, User

class OrganizationMiddleware(object):

  def process_view(self, request, view_func, view_args, view_kwargs):
    header_token = request.META.get('HTTP_AUTHORIZATION', None)
    if header_token is not None:
      try:
        token = sub('Token ', '', request.META.get('HTTP_AUTHORIZATION', None))
        token_obj = Token.objects.get(key = token)
        request.user = token_obj.user
      except Token.DoesNotExist:
        pass
    #This is now the correct user
    print (request.user)

这也可以用于进程视图或进程请求。

希望这能帮助将来的人。

相关问题 更多 >