2008-11-23 59 views
47

我想向我的Django編碼網站添加一些Ajax-niceness。Django身份驗證和Ajax - 需要登錄的URL

在我的Django代碼中,我使用django.contrib.auth.decorators@login_required修飾符來標記哪個視圖需要身份驗證。未經身份驗證的用戶單擊它時的默認行爲是將其重定向到登錄頁面,然後傳遞目標頁面。

我在一些網站上看到的,真的很喜歡的是,當用戶點擊一個鏈接導致一個地方被限制爲只能記錄用戶,而不是被重定向到登錄頁面時,他/她會得到一個彈出窗口(通過JavaScript)要求他/她登錄或註冊。沒有重定向部分,所以如果他/她確定他/她真的不喜歡該網站足以浪費註冊時間,則不需要用戶使用「後退」鍵。

所以,問題是:你將如何管理自動將某些鏈接標記爲「受限」的任務,以便JavaScript可以處理它們的onclick事件並顯示「請登錄」彈出窗口?

回答

53

I我面臨着同樣的問題,並且像你一樣,我想要一個簡單的裝飾器來包裝Django ajax視圖,以便像處理其他視圖一樣處理身份驗證。對我來說,看起來很有前途的一種方法是將這樣的裝飾器與JavaScript結合使用,在響應中尋找特定的值。

這裏是第一修訂裝飾的草案:

from functools import wraps 

def ajax_login_required(view_func): 
    @wraps(view_func) 
    def wrapper(request, *args, **kwargs): 
     if request.user.is_authenticated(): 
      return view_func(request, *args, **kwargs) 
     json = simplejson.dumps({ 'not_authenticated': True }) 
     return HttpResponse(json, mimetype='application/json') 
    return wrapper 

這裏是視圖:

@ajax_login_required 
def ajax_update_module(request, module_slug, action): 
    # Etc ... 
    return HttpResponse(json, mimetype='application/json') 

這裏是JavaScript(jQuery的):

$.post('/restricted-url/', data, function(json) { 
    if (json.not_authenticated) { 
     alert('Not authorized.'); // Or something in a message DIV 
     return; 
    } 
    // Etc ... 
}); 

編輯:我試圖按照建議使用functools.wraps。我實際上並沒有在工作代碼中使用這個裝飾器,所以要小心可能的錯誤。

5

聽起來像一個頁面模板可能性。

  1. 你可以通過一個LINK_VIA(或某事),你提供儘可能onClick="return popup(this, 'arg')"None。每個鏈接將是<A HREF="link" {{LINK_VIA}}>some text</a>

    • 對於匿名會話,LINK_VIA有一個值。
    • 對於會議記錄,LINK_VIA是無
  2. 你可以使用一個{% if %}聲明在你的<A HREF=...>標籤。這似乎羅嗦。

  3. 您可以編寫自己的自定義標籤爲{% link_via %}。我對此不夠熟悉,但是您可以將鏈接和文本作爲字符串提供,並且您的代碼可以生成兩種鏈接中的一種。

+0

什麼我不知道是怎麼從模板的角度確定鏈接導致的視圖是否用@login_required裝飾或不... – kender 2008-11-23 22:07:05

+0

該模板沒有隨機鏈接。它具有您在模板中專門設計和編碼的特定鏈接。我建議你改變你在模板中專門放置的每個鏈接。 – 2008-11-23 22:27:21

5

我會同意S.Lott

使模板檢查,如果用戶登錄,只是把鏈接像往常一樣,如果沒有,把像

<a href="{{link}}" onclick="return login_popup()"> 

如果用戶說取消,login_popup將返回false。

Jinja2macros之間,這可能會更容易完成。

如果模板不知道哪些URL需要用戶登錄,那麼您可能需要重新考慮您的設計。

如果你肯定,我想你可以做同樣的事情,django網址調度程序發現視圖函數。
請參閱:django.core.urlresolvers

一旦您已經抓住視圖函數,您可以檢查它是否用@login_required裝飾。

這可能會在自定義標記中完成。
如果你使用Jinja2,你不需要標籤,只需實現該功能並將其暴露給環境,這很簡單,但你必須做一些閱讀Jinja2的API)

+0

我對這個派對狂熱地遲到了,但是無論如何:這只是因爲用戶可以直接鏈接到所討論的頁面,這種情況下,需要登錄所需的彈出方法將會中斷。 – 2013-01-31 19:23:53

1

這裏建議用保鮮.__ doc__會給出裝飾的版本,包裝.__ name__

from functools import wraps 

def ajax_login_required(function): 
    def wrap(request, *args, **kwargs): 
     if request.user.is_authenticated(): 
      return function(request, *args, **kwargs) 
     json = simplejson.dumps({ 'not_authenticated': True }) 
     return HttpResponse(json, mimetype='application/json') 
    wrap.__doc__ = function.__doc__ 
    wrap.__name__ = function.__name__ 
    return wrap 
0

內置斷Eric Walker's解決方案,但Django的2.0

# Standard Imports 
import functools 
import django.http 

def ajax_login_required(view_func): 
    @functools.wraps(view_func) 
    def wrapper(request, *args, **kwargs): 
     if request.user.is_authenticated: 
      return view_func(request, *args, **kwargs) 

     return django.http.JsonResponse('Unauthorized', status=401, safe=False) 

    return wrapper