Fork me on GitHub

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插件。
posted @ 2019-11-13 14:31  是阿凯啊  阅读(143)  评论(0编辑  收藏  举报