2014-02-13 59 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