初谈dango的post提交csrf设置和文件上传
分类:
IT文章
•
2023-11-14 22:08:24
一、CSRF
在django中配置了中间件CsrfViewMiddleWare,每次post请求都post请求的话,都需要在form表单中加入{{ csrf_token }},它的运行原理是
在form表单中生成一个隐藏的input标签
在post的请求头中把csrftoken加入cookie中
从上图可以看出来,两个键值对都不相同,验证的原理是:
cookie是保存在浏览器本地的获取之后时是不会变化的,而隐藏在form表单中的csrfmiddlewaretoken是每次请求都会发生变化的,但是在server端解出来的secret是一致的就表示csrf验证通过。
post请求使用form表单提交数据比较简单只需要在form中加入{% csrf_token %},POST请求使用Ajax提交时使用 以下的方法
方法1:
通过获取隐藏的input标签中的csrfmiddlewaretoken值放在data发送。
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
def index(request):
if request.method == 'GET':
return render(request,'login.html')
else:
csrf = request.POST.get('csrfmiddlewaretoken')
return HttpResponse(csrf)
views.py
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/login/">
<!--必须加上这个应该这个还有Ajax的值是从这个获取的,并且POST的cookie携带csrftoken也是这个的作用-->
{% csrf_token %}
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
$("#id_button").click(function () {
$.ajax({
url:'/login/',
data:{'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()},
type:"POST",
success:function (arg) {
alert(arg);
}
})
})
</script>
</body>
</html>
login.html
注意form标签中的{% csrf_token %}不能删除。
方法2:
在Ajaxsetup配置提交,只需在AjaxSetup中配置
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}'},
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/login/">
<!--必须加上这个应该这个还有Ajax的值是从这个获取的,并且POST的cookie携带csrftoken也是这个的作用-->
{% csrf_token %}
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
// 第二种方式
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ csrf_token }}'},
});
$("#id_button").click(function () {
$.ajax({
url: '/login/',
// data:{'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()},
type: "POST",
success: function (arg) {
alert(arg);
}
})
})
</script>
</body>
</html>
login.html
方式3:
前端也能操作后端返回的cookies,所获取响应头中的cookies中csrftoken字段的值放在响应头中,操作cookies需要引入jquery.cookie.js插件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/login/">
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
$("#id_button").click(function () {
$.ajax({
url: '/login/',
// data:{'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()},
type: "POST",
// 第三种方式在请求头中,这个直接从响应的中获取cookie所以不需要设置{% csrf_token %}
headers: {"X-CSRFToken": $.cookie('csrftoken')},
success: function (arg) {
alert(arg);
}
})
})
</script>
</body>
</html>
login.html
这个是通过响应中的cookies获取csrftoken字段的值提交的,所以不需要{% csrf_token %}配置
注意在请求头中为键为“X-CSRFToken”
每个Ajax请求都要设置头不方便,可以设置一个通用头信息,就可以不用每次都在Ajax请求的头里面配置了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/login/">
{% csrf_token %}
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="button" value="button">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
var csrftoken = $.cookie('csrftoken');
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$("#id_button").click(function () {
$.ajax({
url: '/login/',
type: "POST",
success: function (arg) {
alert(arg);
}
})
})
</script>
</body>
</html>
login.html
注意,这里如果不配置{% csrf_token %}响应头里面不会有set-cookie,发送post的请求里面也就没有csrftoken的值,但是方式三种且不需要配置{% csrf_token %}不知道是什么原因 。
二、文件的上传
讲文件的上传之前,需要先了解一下啊请求头的ContentType的类型
2.1、contentType类型
1 application/x-www-form-urlencoded
这是最常见的POST提交数据的方式。浏览器的原生<form>表单默认使用的就是这中类型
默认的form表单提交数据请求头是application,响应头是text/html的格式
在server端解析出的数据
multipart/form-data 这个是文件通过原生的form表单上传的时候设置了enctype/multipart/form-data时请求头的信息
ajax发送数据,Ajax默认请求头是application,响应头是text/html的类型,和原生form提交数据是一样的,但是Ajax可以配置为其他的类型
Ajax配置contentType为JSON格式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form >
{% csrf_token %}
<input type="file" name="aabb">
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="button" value="submit">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
$("#id_button").click(function () {
$.ajax({
url: '/login/',
// data:{'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()},
type: "POST",
// 配置为JSON发送的就是JSON字符串了
contentType:'JSON',
data:JSON.stringify({'username':$("#id_username").val(),'password':$("#id_password").val()}),
// data:{'username':$("#id_username").val(),'password':$("#id_password").val()},
// 第三种方式在请求头中,这个直接从响应的中获取cookie所以不需要设置{% csrf_token %}
headers: {"X-CSRFToken": $.cookie('csrftoken')},
success: function (arg) {
alert(arg);
}
})
})
</script>
</body>
</html>
login.html
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
def index(request):
if request.method == 'GET':
return render(request,'login.html')
else:
csrf = request.POST.get('csrfmiddlewaretoken')
print(csrf)
username=request.POST.get('username')
print(request.POST.get('username'))
print('POST',request.POST)
print('body',request.body)
return HttpResponse(username)
views.py
server端收到的也为JSON字符串,并且因为reques.POST无法解析JSON数据打印为一个空列表
基于form表单的文件上传
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/login/" enctype="multipart/form-data" method="post">
{% csrf_token %}
<input type="file" name="aabb">
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="submit" value="submit">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<!--<script>-->
<!--$("#id_button").click(function () {-->
<!--$.ajax({-->
<!--url: '/login/',-->
<!--// data:{'csrfmiddlewaretoken':$("[name='csrfmiddlewaretoken']").val()},-->
<!--type: "POST",-->
<!--// 配置为JSON发送的就是JSON字符串了-->
<!--contentType:'JSON',-->
<!--data:JSON.stringify({'username':$("#id_username").val(),'password':$("#id_password").val()}),-->
<!--// data:{'username':$("#id_username").val(),'password':$("#id_password").val()},-->
<!--// 第三种方式在请求头中,这个直接从响应的中获取cookie所以不需要设置{% csrf_token %}-->
<!--headers: {"X-CSRFToken": $.cookie('csrftoken')},-->
<!--success: function (arg) {-->
<!--alert(arg);-->
<!--}-->
<!--})-->
<!--})-->
<!--</script>-->
</body>
</html>
login.html
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
import json,os
from django.conf import settings
def index(request):
if request.method == 'GET':
return render(request,'login.html')
else:
csrf = request.POST.get('csrfmiddlewaretoken')
print(csrf)
username=request.POST.get('username')
print(request.POST.get('username'))
#原始数据
# print('body',request.body)
print('POST',request.POST)
print('files',request.FILES)
#保存文件
#获取文件对象
file_obj = request.FILES.get('aabb')
file_name = file_obj.name #获取文件名
#不设置目录保存在根目录下
path=os.path.join(settings.BASE_DIR, 'media', 'img')
if not os.path.exists(path):
os.makedirs(path)
with open(f'{path}//{file_name}', 'wb') as f:
for chunks in file_obj.chunks():
f.write(chunks)
return HttpResponse(username)
views.py
server接受的数据部分
ajax上传文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form>
{% csrf_token %}
<input id="id_file" type="file" name="aabb">
<input id="id_username" type="text" name="username">
<input id="id_password" type="password" name="password">
<input id="id_button" type="button" value="submit">
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
$("#id_button").click(function () {
var formdata = new FormData();
formdata.append('username',$("#id_username").val());
formdata.append('password',$("#id_password").val());
formdata.append('aabb',$("#id_file")[0].files[0]);
$.ajax({
url: '/login/',
type: "POST",
data:formdata, //将添加好数据的formdata放到data这里
processData: false , // 不处理数据
contentType: false, // 不设置内容类型
// 第三种方式在请求头中,这个直接从响应的中获取cookie所以不需要设置{% csrf_token %}
headers: {"X-CSRFToken": $.cookie('csrftoken')},
success: function (arg) {
alert(arg);
}
})
})
</script>
</body>
</html>
login.html
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
import json,os
from django.conf import settings
def index(request):
if request.method == 'GET':
return render(request,'login.html')
else:
csrf = request.POST.get('csrfmiddlewaretoken')
print(csrf)
username=request.POST.get('username')
print(request.POST.get('username'))
#原始数据
# print('body',request.body)
print('POST',request.POST)
print('files',request.FILES)
#保存文件
#获取文件对象
file_obj = request.FILES.get('aabb')
file_name = file_obj.name #获取文件名
#不设置目录保存在根目录下
path=os.path.join(settings.BASE_DIR, 'media', 'img')
if not os.path.exists(path):
os.makedirs(path)
with open(f'{path}//{file_name}', 'wb') as f:
for chunks in file_obj.chunks():
f.write(chunks)
return HttpResponse(username)
views.py