2014-02-13 127 views
0

我已經建立了使用Django的Web框架的Web應用程序。爲了安全起見,我創建了一些中間件來確保每個URL都受密碼保護。如果一些隨機的人員輸入了webapp的URL,但沒有登錄,中間件會將他們踢到登錄頁面。Django - per url認證?

現在我想建立一個iOS應用程序將從運行於較大的Web應用程序相同的服務器發佈和訪問數據/。這個想法是iOS應用程序將對服務器進行URL調用,並且服務器將吐出返回的JSON數據。我正在用PhoneGape構建應用程序,所以它在jQuery中的所有直接URL調用。

問題是,由於Web應用程序需要用戶登錄才能做任何事情,我需要一些方法來允許iOS應用程序發出數據請求並讓服務器以某種方式驗證此請求是否被允許,即使用戶沒有登錄。基本上是按照URL驗證(但不記錄用戶)的行。

我認爲我最好的選擇是使用相同的中間件,但擴展它,以便任何通過該URL開始的URL以/m/ios/開頭的處理方式不同。從應用程序方面,我可以擁有它,這樣它要求任何URL,它也重視了username和用戶到該URL的password。因此,中間件可以刪除用戶名/密碼並驗證其有效用戶,但不會登錄用戶並簡單地執行請求。

這是處理這種情況的一個合乎邏輯的方式?有沒有更好的辦法?


編輯我應該說,我對接近這一相當開放不同,如果我在做什麼是不適當的/不安全


這是我的中間件文件的樣子,但它不工作正確。驗證有效,但最終對URL的調用尚未完成。

from django.contrib.auth.views import login 
    from django.contrib.auth import authenticate 
    from django.http import HttpResponseRedirect, HttpResponse 
    from django.utils import simplejson 
    from django.core import serializers 

    class SiteLogin: 
     "This middleware requires a login for every view" 
     def process_request(self, request): 
      if request.path != '/accounts/login/' and request.user.is_anonymous(): 
       try: 
        url = request.path.split('/')[1] 
        url = url + '/' + request.path.split('/')[2] + '/' 
        print(url) 
        if url == 'm/ios/': 
         usr = request.GET['username'] 
         psw = request.GET['password'] 
         user = authenticate(username = usr, password = psw) 
         if user is not None: 
          if user.is_active: 
           # This line doesn't actually carry out the request 
           return login(request) 
         else: 
          d = {} 
          d['creds_good'] = "false" 
          json = simplejson.dumps(d) 
          GET = request.GET 
          callback = GET.get('callback') 

          if callback: 
           json = '%s(%s)' % (callback, json) 

          return HttpResponse(json, mimetype='application/json') 
       except: 
        pass 

       if request.POST: 
        return login(request) 
       else: 
        return HttpResponseRedirect('/accounts/login/?next=%s' % request.path) 
+0

是否有一個原因,你不想登錄用戶的ios請求? – toad013

+0

是否可以登錄它們並讓該會話保持登錄狀態,即使在具有小區覆蓋範圍的手機應用程序中?該登錄會話持續多久?會不會有與他們失去細胞接收問題?基本上我認爲最好是做一次性認證來保持用戶的「移動」這麼說。我想我並沒有真正回答你的問題,我只是認爲這不是最好的主意...... – Garfonzo

+0

在URL上傳遞密碼是非常不安全的。它很容易受到URL嗅探。正如@ toad013提到的,如果您使用普通的Django身份驗證,您可以登錄並在每個請求中傳遞Cookie。 – arocks

回答

1

的Django有login_required裝飾,您可以使用此。 您可以將網址映射到某些網址需要登錄而其他網址不需要登錄

+0

但我有很多網址,如前所述,有一個「需要登錄」的毯子。所以這不是真的適用。 – Garfonzo

0

我不會將用戶名和密碼放在請求的網址中。這些東西可以看成明文。這也讓我相信你是iOS應用緩存我的用戶名和密碼。這本身就是一種安全風險。

根據您當前的中間件的邏輯,你還是登錄用戶。它看起來像是你爲每個ios請求的每個URL登錄用戶,爲每個登錄/ url創建一個新的會話。

如果你的應用程序不支持http cookies,那麼傳遞somesort的密鑰或標記是最好的方法,基本上與cookie相同,但手動執行。我會盡量利用django的會話和auth儘可能。在ios應用程序中,我會收集用戶名和密碼並立即致電登錄。理想情況下它會返回一個持久的會話(https://docs.djangoproject.com/en/dev/topics/http/sessions/#django.contrib.sessions.backends.base.SessionBase.set_expiry)到iOS應用程序,該應用程序將只存儲返回的會話密鑰。您將使用哪種身份驗證代替所有其他請求的用戶名/密碼憑據。只要手機保留了會話密鑰,手機就不會收到會話,會話也不會停留在服務器上的手機上。

如果可能的話,我會在所有請求的標題中附加會話密鑰(爲了這個例子我將調用標題DJANGO_SESSION_KEY),這樣它就可以在所有類型的請求(POST ,GET,PUT等。)

然後我會擴展django的會話中間件並重寫process_request函數。在我使用的版本的django(1.5)中,我會更改process_request函數中尋找session_key的行。

class MySessionMiddleware(SessionMiddleware):             
    def process_request(self, request):            
     engine = import_module(settings.SESSION_ENGINE)        
     session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME, request.META.get('HTTP_DJANGO_SESSION_KEY')) 
     request.session = engine.SessionStore(session_key) 

然後我會使用這個自定義擴展會話中間件來代替settings.py中的django's。

然後,您的自定義中間件就會在請求中間件鏈的末尾定義它。

def process_request(self, request):             
    if request.path != '/accounts/login/' and request.user.is_anonymous():   
     if request.META.HTTP_CONTENT_TYPE == 'application/json' or request.META.HTTP_ACCEPT == 'application/json': 
      # return json error response           
     # return error redirect