django为用户实现防止跨站请求伪造的功能,通过中间件 django.middleware.csrf.CsrfViewMiddleware来完成。
1.django中常用的中间件?
- process_request
- process_view
- process_response
- process_exception
- process_render_template
2. 使用中间件做过什么?
- 权限
- 用户登录验证
- django的csrf是如何实现?
process_view方法
- 检查视图是否被 @csrf_exempt (免除csrf认证)
- 去请求体或cookie中获取token
3,django中设置防跨站请求伪造功能有分为全局和局部;
3.1,全局设置,但是对某一个函数不进行csrf认证;
settings中设置全局应用;
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
在视图函数中加上装饰器对函数进行去除验证;
from django.views.decorators.csrf import csrf_exempt @csrf_exempt def users(request): user_list = ['alex','oldboy'] return HttpResponse(json.dumps((user_list)))
3.2,全局不设置,但是对某一个函数进行csrf认证;
全局中注释掉;
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
视图中加上验证;
from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_protect def users(request): user_list = ['alex','oldboy'] return HttpResponse(json.dumps((user_list)))
总结:csrf使用django的中间件来实现,实际上是在process_view方法中实现的,而且是在views函数被执行之前进行的验证;当用户的请求到达视图函数之前会先检查视图函数在以上两种情况下是否需要通过或者免除csrf验证,然后再进行view函数的执行;
1次来访问的时候(get方法),先拿到字符串;下次再来访问的时候(post方法)也必须带着这一串字符串才能成功。
CSRF是指提交数据的时候必须通过验证。
cookie和session是关于用户名/密码保存的。
CSRF字符串不仅在表单里面有了,在cookie里面也有了。
当用form表单提交的时候,把随机字符串和cookie值都发过去了。
如果用Ajax往后台发数据的时候,只需要把cookie值拿到,放到请求头里面发过去就可以了。
加cookie值的Ajax请求过程:
带上随机字符串的话, 才能登录成功。从cookie里面先把随机字符串获取到。获取方法如下:$.cookie('csrftoken'),具体方法如代码所示
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <form action="/login/" method="post"> 9 {% csrf_token %} 10 <input type="text" name="user" placeholder="user"/> 11 <input type="password" name="pwd" placeholder="pwd"/> 12 <input type="checkbox" name="rmb" value="2">10秒免登陆 13 <input type="submit" value="提交"/> 14 <input type="button" id="but1" value="按钮"/> 15 <input type="button" id="but2" value="按钮"/> 16 </form> 17 <script src="/static/jquery-1.12.4.js"></script> 18 <script src="/static/jquery.cookie.js"></script> 19 <script> 20 $(function () { 21 $.ajaxSetup({ 22 beforeSend: function (xhr, settings) { 23 xhr.setRequestHeader('X-CSRFtoken', $.cookie('csrftoken')) 24 } 25 }); 26 27 $('#but1').click(function () { 28 $.ajax({ 29 url: '/login/', 30 type: 'POST', 31 data: {'user': 'root', 'pwd': '123'}, 32 success: function (arg) { 33 } 34 }) 35 }) 36 }) 37 </script> 38 </body> 39 </html>
不加没有加cookie值的Ajax请求过程:报错通不过CSRF验证,报403错误
但是后台需要通过key去获取这个值,那么这个值对应的key是什么呢?通过打印settings.CSRF_HEADER_NAME可知,
key是HTTP_X_CSRFTOKEN, HTTP_ 是django自动给加上的,所以我们发送的时候,只需要把key设置成 X_CSRFTOKEN就可以了。
由于请求头里面不能出现下划线,所以最终设置的时候应该写成 X-CSRFTOKEN。
理论上我们把请求头设置成X_CSRFTOKEN 就可以了。
但是由于Django有要求,请求头里面不能出现下划线,所以最终我们把请求头设置成X-CSRFTOKEN 的样子。
按照官网推荐,建议写成
X-CSRFtoken。
1 headers:{'X-CSRFtoken':$.cookie('csrftoken')},
Form表单提交与Ajax方法提交的不同之处在于,去不同的地方拿csrf_token
在 Ajax中写headers太麻烦了,可以用setup 对整个页面中所有的Ajax操作做一个配置。
表示在发送ajax之前,会先执行一下那个函数。
xhr是XMLHttpRequest 对象,所有的ajax操作底层用的都是它。
而对于django中设置防跨站请求伪造功能有分为全局和局部。
全局:
中间件 django.middleware.csrf.CsrfViewMiddleware
局部:
注:from django.views.decorators.csrf import csrf_exempt,csrf_protect
- @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
- @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
1.中间件,在其它程序中,有的叫管道,有的叫http handler。下面是原生的中间件
写中间件,新建文件夹Middle,新建m1.py
在setting里注册中间件,1个类就是1个中间件
做测试,看是否所有的请求过来时,都必须一一经过中间件。(写了一个test函数)
当想拿返回值的时候,可以通过response函数。request里面存放的是客户端的所有数据,可以有request.GET,request.POST,request.method等方法。
通过第一个中间件的时候,就可以判断一下,是否携带了请求头(CSRFtoken),如果没有带请求头的话,在第1步就可以终止了。
完善我们自己写的中间件。其实中间件就是一个普通的类。
整个请求的流程如下:1.10版本,到哪个中间件发生了阻断,就从哪个中间件返回。
注意process_request, process_response 2个函数名是写死的,不能变。
解析process_view函数的意义
def process_view(self,request,view_func,view_func_args,view_func_kwargs):
view_func:指的就是URL中对应的那个函数,在这里指test函数
view_func_args:对应test函数中接收的参数,对应的URL如下:url(r'^test/(d+)$', views.test), def test(request,nid)
view_func_kwargs:对应test函数中接收的字典,对应的URL如下:url(r'^test/(?P<nid>d+)$', views.test), def test(request,nid)
def process_exception(self,request,exception): 这个函数一般情况下不执行,只有在出错时才执行。指的是异常信息
def process_template_response (self,request,response): 默认情况下也不执行,
如果views中的函数返回的对象中,具有render方法,那这个函数就会执行了。
process_Request, 发出请求
process_view, 通过以后,就会达到view函数
process_response, 开始返回。