2012-09-28 37 views
3

我正在爲每個客戶重寫一個具有數據庫的遺留應用程序。每個客戶都有自己的認證和用戶組。因此,我需要一個自定義身份驗證後端,因爲django的身份驗證設置爲只使用默認值。我編寫了一些中間件,可以在每次請求時檢查url並提取信息以在請求上設置database_name。Django驗證後端多個數據庫

如果我在處理自定義認證後端期間訪問請求,我可以很容易地執行數據庫調用user = User.objects.using(request.db).get(username=username)但是,我沒有看到簡單的方法來完成此操作。我在這裏看到了一個答案:Access request.session from backend.get_user,但這看起來不是線程安全的,所以我不想走這條路。

我能看到的仍然使用django-auth的唯一解決方案是爲每個設置數據庫名稱以用作類屬性的客戶擁有身份驗證後端。然後,我將創建一個自定義登錄函數,將request.session ['_ auth_user_backend']設置爲客戶特定的後端。因此,當每個請求調用get_user(user_id)時,它將使用客戶後端,它知道要從哪個數據庫請求。

我想避免爲每個客戶管理身份驗證後端,如果可能的話。有一個更好的方法嗎?

回答

7

由於auth後端未調用QuerySet方法using,因此可以使用database routerthread local變量以及一些中間件將變量設置爲客戶的數據庫名稱。中間件必須放置在認證中間件之前。

線程局部變量是線程安全的。它創建一個線程局部全局變量。

如果你是以下請求的路徑,將做到以下幾點:

  1. 請求命中Django的
  2. 您的自定義中間件抓取URL中的數據庫名稱將它設置爲線程局部全局變量。
  3. django認證中間件通過運行查詢User.object.get(id=user_id)啓動並設置用戶。這將使用你的數據庫路由器,它將只返回在以前的中間件中設置的線程局部全局變量。

  4. 該請求繼續進入django堆棧的其餘部分。

例如您有以下模塊:

程序my_app/middleware.py

from threading import local 

my_local_global = local() 

class CustomerMiddleware(object): 
    def process_request(self, request): 
     my_local_global.database_name = get_database_name(request) 

程序my_app/routers.py

from middleware import my_local_global 

class MultiCustomerRouter(object): 
    def db_for_read(self, model, **hints): 
     return my_local_global.database_name 

設置。py

... 
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware', 
'django.contrib.sessions.middleware.SessionMiddleware', 
'django.middleware.csrf.CsrfViewMiddleware', 
'my_app.middleware.CustomerMiddleware', 
'django.contrib.auth.middleware.AuthenticationMiddleware', 
'django.contrib.messages.middleware.MessageMiddleware', 
) 

DATABASE_ROUTERS = ['my_app.routers.MultiCustomerRouter'] 
... 
2

可能你可以用Django database routers來控制它。如果您知道哪個用戶點擊了哪個數據庫,您可以簡單地根據用戶模型的邏輯來定義該數據庫。

+0

路由器是一個有趣的想法。我以前用過他們,但我不認爲他們會在'高清GET_USER(個體經營,USER_ID)期間幫助:'調用AUTH後端。發生此通話時,我無法訪問該請求,只有一個身份證件才能啓動。除非我徹底改變後端,否則我怎麼知道該指向哪裏?我認爲那可能不是一個更好的方法。 :( – DivineSlayer