2012-02-12 109 views
10

我想我的android应用程序能够发送一些信息到我的django服务器。所以我让android应用程序向mysite/upload页面发送了一个post请求,而django对这个页面的看法会根据post数据做一些工作。问题是服务器对post请求的回应抱怨csrf验证失败。寻找这个问题,似乎我可能必须先从服务器获取csrf令牌,然后使用该令牌进行发布但我不确定我是如何做到这一点的。编辑:我已经发现,我可以使用视图装饰器@csrf_exempt剔除此视图的crsf验证,但我不确定这是否是最佳解决方案。我的Android代码:Android发送请求到Django服务器csrf失败

// Create a new HttpClient and Post Header 
        HttpClient httpclient = new DefaultHttpClient(); 
        HttpPost httppost = new HttpPost(URL); 

        // Add your data 
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); 
        nameValuePairs.add(new BasicNameValuePair("scoreone", scoreone)); 
        nameValuePairs.add(new BasicNameValuePair("scoretwo", scoretwo)); 
        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 
        System.out.println("huzahhhhhhh"); 
        // Execute HTTP Post Request 
        HttpResponse response = httpclient.execute(httppost); 
        BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); 
        StringBuffer sb = new StringBuffer(""); 
        String line = ""; 
        String NL = System.getProperty("line.separator"); 
        while ((line = in.readLine()) != null) { 
         sb.append(line + NL); 
        } 
        in.close(); 
        String result = sb.toString(); 
        System.out.println("Result: "+result); 

和处理上传我的看法代码:

# uploads a players match 
def upload(request): 
    if request.method == 'POST': 
     scoreone = int(request.POST['scoreone']) 
     scoretwo = int(request.POST['scoretwo']) 
     m = Match.objects.create() 
     MatchParticipant.objects.create(player = Player.objects.get(pk=1), match = m, score = scoreone) 
     MatchParticipant.objects.create(player = Player.objects.get(pk=2), match = m, score = scoretwo) 
    return HttpResponse("Match uploaded") 

enter code here 
+0

我得到403错误,我做同样的事情。 如果你已经解决了错误,你能帮助我吗? – 2014-06-19 11:41:12

回答

2

写自己的装饰和添加一些“秘密”标题您的要求。 https://code.djangoproject.com/browser/django/trunk/django/views/decorators/csrf.py

def csrf_exempt(view_func): 
     """ 
     Marks a view function as being exempt from the CSRF view protection. 
     """ 
     # We could just do view_func.csrf_exempt = True, but decorators 
     # are nicer if they don't have side-effects, so we return a new 
     # function. 
     def wrapped_view(request,*args, **kwargs): 
      return view_func(request, *args, **kwargs) 
      if request.META.has_key('HTTP_X_SKIP_CSRF'): 
       wrapped_view.csrf_exempt = True 
     return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view) 
+3

你在这里绕过安全。 – remus 2016-01-08 19:24:12

+1

@remus CSRF for Android应用没有任何意义。跨网站请求伪造的是古典网页。它对API的废话。 – iddqd 2016-05-19 19:00:22

2

关闭CSRF验证肯定有效!但你确定你想这么做吗?你原来的思路;从服务器获取令牌并将其与POST数据一起发送要好得多。

csrf标记通常以cookie的形式存在。例如,在Django框架中,您有一个名为csrftoken的cookie,您需要获取该值并将其作为'X-CSRFToken'发布到服务器上。

10

首先,您需要从预览请求中的cookie中读取csrf标记:

httpClient.execute(new HttpGet(uri)); 
CookieStore cookieStore = httpClient.getCookieStore(); 
List <Cookie> cookies = cookieStore.getCookies(); 
for (Cookie cookie: cookies) { 
    if (cookie.getDomain().equals(Constants.CSRF_COOKIE_DOMAIN) && cookie.getName().equals("csrftoken")) { 
     CSRFTOKEN = cookie.getValue(); 
    } 
} 

如果你的观点并没有渲染包含csrf_token 模板标签模板,Django的,还没有设置CSRF令牌的cookie。在表单动态添加到页面的情况下,这是 。到 解决这个问题,Django提供了一个视图装饰器,它强制设置cookie的 :ensure_csrf_cookie()。 - https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax

然后,你可以做POST请求时,它通过对POST请求头和cookie的服务器:

httpPost.setHeader("Referer", Constants.SITE_URL); 
httpPost.setHeader("X-CSRFToken", CSRFTOKEN); 

DefaultHttpClient client = new DefaultHttpClient(); 
final BasicCookieStore cookieStore = new BasicCookieStore(); 

BasicClientCookie csrf_cookie = new BasicClientCookie("csrftoken", CSRFTOKEN); 
csrf_cookie.setDomain(Constants.CSRF_COOKIE_DOMAIN); 
cookieStore.addCookie(csrf_cookie); 

// Create local HTTP context - to store cookies 
HttpContext localContext = new BasicHttpContext(); 
// Bind custom cookie store to the local context 
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); 

HttpResponse response = client.execute(httpPost, localContext); 
+0

我正在做同样的事情,但我得到403错误。 我已经尝试发送cookie,headers.but仍然收到相同的错误。 – 2014-06-19 11:40:10

+0

这对我来说非常出色,谢谢! – 2015-02-09 23:49:46