我希望我的Android应用能够将一些信息发送到我的django服务器。所以我让android应用程序发送一个帖子请求到mysite / upload页面,django的这个页面的视图将根据帖子数据工作。问题是服务器为post请求提出的响应抱怨csrf验证失败。看看问题,似乎我可能必须首先从服务器获取一个csrf令牌,然后使用该令牌执行帖子但是我不确定我是如何做到的。编辑:我发现我可以使用视图装饰器@csrf_exempt来解决此视图的crsf验证,但我不确定这是否是最佳解决方案。我的android代码:
// 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 :(得分: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
然后,您可以在执行发布请求时将其传递到发布请求标头和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);
答案 1 :(得分: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)
答案 2 :(得分:2)
关闭CSRF验证肯定有效!但你确定要这么做吗?你最初的思路;从服务器获取令牌并将其与POST数据一起发送要好得多。
csrf令牌通常以cookie的形式出现。例如,对于Django框架,您有一个名为csrftoken的cookie,您需要获取该值并将其作为“X-CSRFToken”发布到服务器