2014-10-07 64 views
13

我試圖讓中間件這會改變某些領域基於子域的用戶,等等Django和中間件,它使用request.user始終是匿名

唯一的問題是request.user總是作爲AnonymousUser在中間件內,但是在視圖內是正確的用戶。我已經在設置中使用了默認的身份驗證和會話中間件django。

也有同樣的問題在這裏:Django, request.user is always Anonymous User 但因爲我沒有使用不同的認證方法並不過分回答總的問題,之前我調用我自己的中間件Django的認證正在運行。

在使用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 

與process_request:

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 

謝謝!

喬丹

+1

中間件的順序是非常重要的。確保身份驗證中間件在您的設置之前列出 – 2014-10-07 16:32:24

+2

在django運行其默認設置後,我已將它包含在中間件的末尾。 (認證和會話) – Jordan 2014-10-07 16:33:44

+0

你試過用[process_request](https://docs.djangoproject.com/en/dev/topics/http/middleware/#process-request)而不是process_view? – danihp 2014-10-07 16:57:17

回答

16

嗨,我從請求,並裝載到request.user關聯到該模型的用戶越來越DRF令牌解決了這個問題。

我有默認的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) 

這也可以在process_view或process_request上使用。

希望這可以幫助未來的人。

+0

我處於相同的情況,這完美的工作!但是,我仍然想知道,如果這不會導致令牌被中間件後面的任何運行處理一秒鐘以驗證令牌?那不好嗎?我對DRF太陌生了,無論如何也不知道。 – IAmKale 2015-04-15 17:04:14

+1

嘿,所以我發現這不是實現這個最好的方法。實現它的正確方法是將rest_frameworks認證中間件包含在設置中的AUTHENTICATION_BACKENDS中。 ''''rest_framework.authentication.TokenAuthentication'''' – Jordan 2015-06-25 03:31:59

+0

@Jordan你能否詳細說明你的最新評論?我有同樣的問題,並試圖添加TokenAuthentication AUTHENTICATION_BACKENDS,並沒有解決我的問題。如何將其添加到AUTHENTICATION_BACKENDS可以幫助您?謝謝 – baselq 2015-07-28 22:54:49

6

今天遇到這個問題,同時遇到同樣的問題。

TL; DR;

跳過下面的代碼示例


說明

事情是DRF有自己的東西流,就在Django的請求life-cycle的中間。

因此,如果正常中間件流程爲:

  1. request_middleware
  2. view_middleware(調用視圖之前)
  3. template_middleware(前渲染)
  4. response_middleware(在開始對請求工作之前) (在最終響應之前)

DRF代碼覆蓋默認的django視圖co de,並執行their own code

在上面的鏈接中,您可以看到他們用自己的方法包裝了原始請求,其中一種方法是DRF身份驗證。

回到你的問題,這是在中間件中使用request.user的原因爲時過早,因爲它只在 view_middleware **執行後得到它的值

我的解決方案是讓我的中間件設置爲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)) 
+1

我得到'object()不需要參數' – 2017-02-23 00:53:55

+1

你使用的是什麼django?我的解決方案適用於1.9。新的1.10版本對中間件有很多突破性的改變。 檢查了這一點,https://docs.djangoproject.com/en/1.10/releases/1。10 /#新風格的中間件,如果你有任何結論,請發帖(: 我將更新我的原始答案,一旦我移動到1.10以及.. – 2017-02-23 08:00:39

+0

這是一個非常整潔的解決方案!我會發佈一個更新的答案Django 1.11 – 2017-12-06 13:21:15

1

基於丹尼爾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 
相關問題