• 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有两种方式:
    • 必有{%csrf_token%}

      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插件。
  • 相关阅读:
    asp.net中读取带有加号(+)的Cookie,会自动把加号替换为空格
    简单实现分行输出的javascript代码
    大学我们应该做什么
    近日个人要闻
    WPF学习笔记“路由事件”一:路由事件基础
    WPF学习笔记“路由事件”二:路由事件基础
    WPF学习笔记“命令”三:执行命令
    WPF学习笔记“命令”二:命令库
    WPF学习笔记“命令”五:自定义高级命令的使用
    WPF学习笔记“布局”一:基础
  • 原文地址:https://www.cnblogs.com/xujunkai/p/11848070.html
Copyright © 2020-2023  润新知