Django:Csrf
1.AJAX准备知识
-
什么是JSON?
- JSON指得是JavaScript对象表示法
- JSON是轻量级的文本数据交换格式
- JSON是独立语言
- JSON具有自我描述性,更容易理解
-
优势:JSON使用JavaScript语法来描述数据对象,但是JSON仍然独立于语言和平台。JSON解析器和JSON库支持许多不同编程语言。
-
JavaScript支持数据类型:数字型,字符串型,布尔类型,数组类型,对象,null
-
Python支持数据类型:整型浮点型、字符串类型、布尔类型、列表类型、字典类型、None
-
合格JSON对象输入方式:
["one","two","three"] {"one":1,"two":2,"three":3} {"name":["曹操","刘备","孙权"]}
-
不合格JSON对象
{"name":"张三",'age':32} //属性名必须使用双引号 [23,44,0xFFF] //不能使用十六进制 {"name":Undefined} //不能使用Undefined
2.字符串&&JSON对象转换方法
-
stringify
- 将JavaScript值转换为JSON字符串
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="text/javascript"> var temp = {"name":"刘备"}; str_temp = JSON.stringify(temp); console.log(str_temp); console.log(typeof str_temp); </script> </body> </html>
-
显示在网页为字符串
-
parse
- 将JSON字符串转换为JavaScript对象
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script type="text/javascript"> var temp = '{"name":"曹操"}'; obj_temp = JSON.parse(temp); console.log(obj_temp); console.log(typeof obj_temp); </script> </body> </html>
-
显示网页为object对象
3.JSON与XML比较
- JSON书写简单、层次清晰、易于阅读。符合JavaScript原生语法,可以由解释引擎直接处理,不用另外添加解析代码。
4.AJAX
-
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的JavaScript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
-
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
-
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
-
AJAX不需要任何浏览器插件,但是需要用户允许JavaScript在浏览器执行。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
-
示例:页面输入两个整数,通过AJAX传输到后端计算出结果并返回。
-
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/jquery.js"></script>
</head>
<body>
<input type="text" name="r1">+
<input type="text" name="r2">=
<input type="text" name="r3">
<button id="b1">提交</button>
<br>
<script type="text/javascript">
//获取点击事件
$("#b1").click(function(){
//ajax处理:$.ajax({})
$.ajax({
url:"/cla/",//请求url
type:"post",//请求方式
data:{
num1:$("[name='r1']").val(),//获取input值
num2:$("[name='r2']").val(),//获取input值
},
//成功就执行,下面函数。
success:function (data) {
$("[name='r3']").val(data)
}
})
})
</script>
</body>
</html>
- views.py
def index(request):
return render(request,"index.html")
def cla(request):
#获取页面值,
num1 = request.POST.get("num1")
num2 = request.POST.get("num2")
print(num1)
print(num2)
#相加
result = int(num1) + int(num2)
#返回给页面
return HttpResponse(result)
5.Csrf的那些事情:
-
{%csrf_token%}在页面生成一个隐藏的input标签。
-
前面操作我们是把settings的MIDDLEWARE的中间件注销掉POST请求才会顺利执行也就是它:
-
当打开中间件,在点击提交时候会报一个CSRF验证失败,请求终止错误。
三种装饰器介绍
-
首先先介绍三个装饰器:
#模块导入: from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie #1 csrf_exempt 某个视图不需要进行csrf校验 csrf_protect 某个视图需要进行csrf校验 ensure_csrf_cookie 确保生成csrf的cookie
-
csrf_exempt
-
使用csrf_exempt表示不需要进行CSRF校验,但注意当为CBV时不能加在方法上也不能加类上面,只能加在dispatch上
##导入模块csrf用户创建csrf装饰器 from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie from django.utils.decorators import method_decorator class Login(View): @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): ret = super().dispatch(request, *args, **kwargs) return ret def get(self,request,*args,**kwargs): return render(request,"login.html") def post(self,request,*args,**kwargs): pass
-
-
csrf_portect
- 当注释掉setting中间件'django.middleware.csrf.CsrfViewMiddleware',使用装饰器csrf_portect,表示该方法需要校验
from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie from django.utils.decorators import method_decorator class Login(View): def get(self,request,*args,**kwargs): return render(request,"login.html") @method_decorator(csrf_protect) def post(self,request,*args,**kwargs): pass
- post方法需要校验但是,我们没有做校验操作。所以报错
-
ensure_csrf_cookie 确保页面生成csrftoken值,在cookie里
也可通过不注释掉django.middleware.csrf.CsrfViewMiddleware,网页设置{%csrf_token%}
- 如果注释掉'django.middleware.csrf.CsrfViewMiddleware',
-
加上装饰器,访问页面
6.中间件django.middleware.csrf.CsrfViewMiddleware的实现(源码分析):
from django.middleware.csrf import CsrfViewMiddleware
from django.conf import global_settings 可以查看global_settings文件
-
总结
第一步:csrf中间件执行process_request做了什么事? 1.从cookie中获取到csrftoken的值。 2.csrftoken值放入到request.META中,请求头 第二步:process_view方法执行又做了什么? 1.查看视图函数是否使用csrf_exepmt装饰器,使用了就不进行csrf校验 2.判断请求方式 如果是GET,HEAD,OPTIONS,TRACE,不进行csrf校验 如果是其他请求,如POST,PUT,进行CSRF校验 1.获取cookie中csrftoken的值 2.POST请求中获取csrfmiddlewaretoken的值: 获取到--->request_csrf_token 获取不到(如PUT,DELETE请求)--->获取请求头中X-csrftoken的值--->request_csrf_token 比较上面2个值,比较成功接收请求,比较不成功失败。
7.ajax的参数和上传文件
#######upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/static/jquery.js"></script>
</head>
<body>
<input type="file" id="f1" name="pic">
<button id="b">上传</button>
<p></p>
<script>
//触发点击事先
$("#b").click(function () {
//新建一个对象
var formobj = new FormData();
//往对象添加键值对
formobj.append("file",document.getElementById("f1").files[0]);
formobj.append("name","xjk");
$.ajax({
url:"/uploadpic/",
type:"post",
data :formobj,
//processData为True,就会成为URLencode数据,不设置urlencode
processData:false,
//请求头设置false,不让它自己设置,自己设置就会成为URLencode编码
contentType:false,
success:function(data){
//上传成功给页面提示上传成功
$("p").text(data)
}
})
})
</script>
</body>
</html>
#view.py页面
def upload(request):
return render(request,"upload.html")
def uploadpic(request):
pic = request.FILES.get("file")
print(pic)
print(request.FILES)
print(request.POST)
with open("pic.png", 'wb') as f:
for item in pic.chunks():
f.write(item)
return HttpResponse("上传成功")
8.ajax通过django的csrf校验的方法(中间件打开)
-
之间例题由于注释掉了settings的MIDDLEWARE的中间件,所以才能提交POST请求,这样并不合理。那么如何让AJAX通过csrf校验。
-
AJAX通过csrf的校验的必须要保证csrftoken的cookie
- 确保csrftoken有cookies有两种方式:
-
必有
1.加装饰器:ensure_csrf_cookies, 2.csrfmiddlewaretoken
方式1:
1.在页面使用{%csrf_token%}#加载时候生成input隐形表单
2.打开'django.middleware.csrf.CsrfViewMiddleware',
3.给ajax中添加csrfmiddlewaretoken
data: {
#获取csrf_token表单的csrfmiddlewaretoken然后提交给服务器
'csrfmiddlewaretoken':$('[name="csrfmiddlewaretoken"]').val(),
a: $("[name='i1']").val(),
b: $("[name='i2']").val(),
}
方式2:
#ajax内加入
headers:{
"x-csrftoken":$('[name="csrfmiddlewaretoken"]').val(),
},
#注意:重新设置CSRF_HEADER_NAME值,也可执行
在setting.py设置
CSRF_HEADER_NAME = "HTTP_ASD"
headers:{
"asd":$('[name="csrfmiddlewaretoken"]').val(),
},
方式3:
通过导入JavaScript实现:方式与方式2相似
//ajax_setpu.js
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
//从本地读取到cookie根据你提供name=csrftoken,获取值。
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
//对全局ajax进行设置,在ajax之前,执行函数。
//在每次发ajax请求前面都要设置请求头X-CSRFToken。
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
- 也可以用jquery.cookie.js插件。