2012-02-12 114 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