zoukankan      html  css  js  c++  java
  • django学习第十二天--ajax请求和csrftoken认证的三种方式

    基于cookie的登录认证装饰器

          def check_login(f):
                def inner(request,*args,**kwargs):
                      is_login = request.COOKIES.get('is_login')
                      if is_login == 'True':
                            ret = f(request)
                            return ret
                      else:
                            return redirect('login')
                return inner
    
          @check_login
          def cart(request):
                return render(request,'cart.html')
    

    基于session的登录认证装饰器

          def check_login(f):
                def inner(request,*args,**kwargs):
                      is_login = request.session.get('is_login')
                      if is_login:
                            ret = f(request,*args,**kwargs)
                            return ret
                      else:
                            return redirect('login')
                return inner
    
          @check_login
          def cart(request):
                return render(request,'cart.html')
    

    sweetalert插件完成ajax删除数据动作

    局部刷新页面进行删除 参考图书管理系统基于ajax请求删除数据

    sweetalert基于bootstrap,所有首先要先导入bootstrap插件,然后把sweetalert下载下来,一般前端开发人员会把插件放在dist文件夹里面,所有我们只要用dist文件夹里面的插件就可以了,其他的都不要
    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
        <link rel="stylesheet" href="{% static 'bootstrap-sweetalert-master/dist/sweetalert.css' %}"> //sweetalert插件css
    </head>
    <body>
    
    <button class="btn btn-danger">删除啦</button>
    
    </body>
    <script src="{% static 'jquery.js' %}"></script>
    <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    <script src="{% static 'bootstrap-sweetalert-master/dist/sweetalert.min.js' %}"></script> //sweetalert插件js
    
    </html>
    
          $('.del').on('click',function(){
                var delete_id = $(this).prev().text() //获取上一个标签的id
                var ths = $(this); //因为下面的函数中this指向的不是我们的标签按钮,所以通过一个全部变量来保存一下这个$(this),方便后面使用
                swal({  //这个sweetalert内部源码 直接拿来用就行,修改下文本内容
                      title:'are you sure?',
                      text:'要谨慎!',
                      type:'warning',
                      showCancalButton:true,
                      confirmButtonClass:'btn-danger',
                      confirmButtonText:'确定删除',
                      cancelButtonText:'容我三思',
                      closeOnConfirm:false
                      },
                      //点击确认删除时触发的函数
                      function(){
                            $.ajax({//路径拼接相当于/ajax_delete_book/1/
                                  url:'/ajax_delete_book/'+delete_id+'/',
                                  type:'get',
                                  success:function(res){
                                        console.log(res);
                                        if (res==='ok'){
                                              //关闭弹窗
                                              swal('删除成功!','你可以准备跑路了!','success');//这个是swal自带的方法
                                              //局部刷新,删除对应记录
                                              ths.parent().parent().remove();
                                              }
                                        }
                            })
                      }
                )
          })
    

    js中的箭头函数

          普通函数:var k = function(参数){return 'kkk'};
          箭头函数:var k =(参数) =>{return 'kkkk'};
          箭头函数简写:var k = (参数) => 'kkkk'
    

    js函数中this的指向问题,面试题

    • 1.箭头函数 会去寻找上下文的this
          var a = 'xx';
          var d1 = {
                a:'ss',
                f:()=>{
                      //this指向函数调用者
                      console.log(this.a); //xx
                },
          }
          d1.f()  #调用者是d1对象,但是里面是箭头函数,所以会去往d1对象上面寻找,即window对象,所以打印的内容为xx
    
    • 2.函数的单体模式
          var a = 'xx';
          var d1 = {
                a:'ss',
                f(){
                      console.log(this.a);
                },
          }
          d1.f()   #调用者是d1对象,打印结果为ss
    
    • 3.没有对象调用,那么this指向的就是window对象
          
          var a = 'xx';
          var d1 = {
                a:'ss',
                f:function(){
                      console.log(this.a); //ss
                      function f1(){
                            console.log(this);//指向了window对象
                            console.log(this.a);//结果为xx
                            }
                      f1()
                },
          }
          d1.f()
    
    • 4.箭头函数,改变this的指向,将this指向上下文的this
          var a = 'xx';
          var d1 = {
                a:'ss',
                f:function(){
                      console.log(this.a); //ss
                      var f1 = ()=>{
                            console.log(this);//指向了d1对象
                            console.log(this.a); //结果为ss
                      }
                      f1()
                },
          }
          d1.f()
          首先d1.f(),d1对象调用f普通函数,那么里面首先会打印ss,然后f1()函数没有调用者,而且还是一个箭头函数,那么就会从上下文寻找this对象,即上一个调用者,即为d1,所以所以f1()函数里面指向的this就为d1,打印结果就为ss
    
    • 5.嵌套箭头函数
          var a = 'xx';
          var d1 = {
                a:'ss',
                f:()=>{
                      console.log(this.a);//xx
                      var f1=()=>{
                            console.log(this);//指向了window对象
                            console.log(this.a); //结果为xx
                            }
                      f1()
                },
          }
          d1.f()
          首先d1.f()调用的是箭头函数,那么就会往上找,即为window对象,所以调用f会打印xx,然后里面又嵌套了一个箭头函数f1,所以f1也会往上找,f1->d1->window,所以f1中this的指向也是window,打印结果为xx
    

    ajax处理请求失败和请求成功的方式

    • html部分代码
    $(".del").on("click", function () {        
          var delete_id = $(this).prev().text();
          var ths = $(this);  //因为下面的函数中this指向的不是我们的标签按钮,所以通过一个变量来保存一下这个$(this),方便后面使用
          swal({
                title: "are you sure?",
                text: "要谨慎!",
                type: "warning",
                showCancelButton: true,
                confirmButtonClass: "btn-danger",
                confirmButtonText: "确定删除",
                cancelButtonText: "容我三思",
                closeOnConfirm: false
          },
          //点击确认删除时触发的函数
          function () {
          $.ajax({
                url:'/ajax_delete_book/'+'100'+'/',//这边暂时写死了100目的是要处理返回请求失败的结果,100对应的其实是要删除的id
                type:'get',
                success:function(res){
                      //当状态码为2xx或者3xx时才认为是请求正常成功了,会触发success对应的函数,但是当状态为4xx/5xx的时候,ajax认为此次请求是失败的会触发error属性对应的函数
                      if (res==='ok'){
                            console.log('okokok');
                            //关闭弹框
                            swal('删除成功!','你可以准备跑路了!','success');
                            //局部刷新,删除对应记录
                            ths.parent().parent().remove();
                            
                       }else{
                            console.log('出错啦!')
                            }
                      };
                error:function(res){
                      if (res.status===404){
                            swal('删除失败!',res.responseText,'error');
                            //res.responseText是后台响应回来的错误信息
                            }
                }
          }
          })
    
    • views视图代码
          def ajax_delete_book(request,pk):
                try:
                      models.Book.objects.get(pk=pk).delete()
                except:
                      return HttpResponse('找不到对应的资源!!!',status=404)#将响应状态码改为404
                return HttpResponse('OK')
    

    CSRF跨站请求

    • cookie执行流程
    • csrf攻击流程
          如何防止csrf攻击呢?我们自己的网站要防止这个事情
          csrftoken机制,csrf攻击的最多的方式
          django已经做好了这个机制
          如下图
    
    • django中的csrf机制

    form表单通过csrftoken认证

    • login.html文件
          <form action='/login/' method='post'>
                {% csrf_token %} //会生成一个隐藏的input标签,value属性里面放着token值,name属性值为csrfmiddlewaretoken
                用户名:<input type='text' name='username'>
                <input type='submit'>
          </form>
          {% csrf_token %}当我们使用from表单标签来发送请求时,如果需要csrftoken认证,那么必须将它写到我们的form表单标签里面,里面的任意位置。
          生成的隐藏标签为:
         <input type="hidden" name="csrfmiddlewaretoken" value="WVHKQeAuMS4RGqyLybryIBAfacDa1Dp7PEaB3Badv3y0fvLqydX36xAVen6z3oS4">
    

    校验过程解释

          html页面中的
          {% csrf_token %}
           <input type="hidden" name="csrfmiddlewaretoken" value="WVHKQeAuMS4RGqyLybryIBAfacDa1Dp7PEaB3Badv3y0fvLqydX36xAVen6z3oS4">
    
          cookie中的
          csrftoken:CeFG6SA8Y8hcHAX5R93sxrS37v3iFFlcvX8xjfaRHjLlgFaKRbzXVnSJbGwHHqO9
    
          注意:它们两个的token值是不相同的,这个不用管,到时发送给后台的时候,django会处理的
    
          django会取出提交数据部分的token值和cookie中的token值进行比较:
          WVHKQeAuMS4RGqyLybryIBAfacDa1Dp7PEaB3Badv3y0fvLqydX36xAVen6z3oS4 --前32位可以对后面的几位进行解密,html中的token解密出secret_key1  一个字符串
    
          CeFG6SA8Y8hcHAX5R93sxrS37v3iFFlcvX8xjfaRHjLlgFaKRbzXVnSJbGwHHqO9 --前32位可以对后面的几位进行解密,cookie中的token解密出secret_key2  一个字符串
          secret_key1 = secret_key2
    
          说明:
                token字符串的前32位是salt盐,后面是加密后的token,通过salt能解密出唯一的secret。
                django会验证表单中的token和cookie中的token是否能解出同样的secret,secret一样则本次请求合法。
    
          MIDDLEWARE = [
    		...
                    'django.middleware.csrf.CsrfViewMiddleware',
    	        ...
                ]
          源码
    def _compare_salted_tokens(request_csrf_token, csrf_token):
        # Assume both arguments are sanitized -- that is, strings of
        # length CSRF_TOKEN_LENGTH, all CSRF_ALLOWED_CHARS.
        return constant_time_compare(
            _unsalt_cipher_token(request_csrf_token),
            _unsalt_cipher_token(csrf_token),
        )
    
    def _unsalt_cipher_token(token):
        """
        Given a token (assumed to be a string of CSRF_ALLOWED_CHARS, of length
        CSRF_TOKEN_LENGTH, and that its first half is a salt), use it to decrypt
        the second half to produce the original secret.
        """
        salt = token[:CSRF_SECRET_LENGTH]
        token = token[CSRF_SECRET_LENGTH:]
        chars = CSRF_ALLOWED_CHARS
        pairs = zip((chars.index(x) for x in token), (chars.index(x) for x in salt))
        secret = ''.join(chars[x - y] for x, y in pairs)  # Note negative values are ok
        return secret
    
    

    ajax请求通过csrftoken认证三种方式

    • 方式1
          首先在html文件中间,写上{% csrf_token %}
          {% csrf_token %}
          用户名: <input type="text" id="uname" >
          <button id="btn">ajax提交</button>
    
          jquey代码
          $('#btn').click(function(){
                var uname = $('#uname').val();
                //获取csrfmiddlewaretoken的input标签value属性对应的值
                var token = $('[name="csrfmiddlewaretoken"]').val();
                
                $.ajax({
                      url:'/login/',
                      type:'post',
                      //将token值放到请求数据部分,token的键必须是csrfmiddlewaretoken
                      data:{uname:uname,csrfmiddlewaretoken:token},
                      success:function(res){
                            console.log(res);
                            }
                })
          })
    
    • 方式2
          使用'{{ csrf_token }}'这个模板渲染标签,这样就不要我们在html页面中写{% csrf_token %}了。
          $('#btn').click(function(){
                var uname = $('#uname').val();
                //直接就能得到csrfmiddlewaretoken的input标签value属性的值
                var token= '{{ csrf_token }}';
    
                $.ajax({
                      url:'/login/',
                      type:'post',
                      data:{uname:uname,csrfmiddlewaretoken:token},
                      success:function(res){
                            console.log(res);
                      }
                })
                })
    
    • 方式3
          借助js操作cookie的方法来获取到cookie中的csrftoken那个键对应的值
          然后将这个值组成一个请求头,放到此次请求中
          headers:{'X-CSRFToken':这个值}
          这个值,通过js能够获取到,通过jquery也能获取到,我们看一下jquery如何操作cookie
          
          操作步骤,下载与引入
          jquery.cookie.js基于jquery;先引入jquery,再引入:jquery.cookie.js;下载:http://plugins.jquery.com/cookie/
          <script src="{% static 'jquery.js' %}"></script> #这个要在上面
          <script src="{% static 'jquery.cookie.js' %}"></script>
    
          
          {% csrf_token %} //需要在html中写上{% csrf_token %}或{{ csrf_token }},不然此次获取这个html页面的时候,响应中不会有这个csrftoken的cookie的值
          $('#btn').click(function(){
                var uname = $('#uname').val();
                //通过js获取jquery来获取cookie中的csrftoken这个键对应的token值
                var token = $.cookie('csrftoken');
                $.ajax({
                      url:'/login/',
                      type:'post',
                      //将获取到的token值放到请求头中,这个请求头键值对的键必须是'X-CSRFToken'
                      headers:{
                            'X-CSRFToken':token,
                      },
                      //django先去获取请求数据部分的token值,获取不到,就去找一个叫做X-CSRFToken请求头键值对,它的值和cookie中的csrftoken的值要相等。
                      data:{uname:uname,},
                      success:function(res){
                            console.log(res);
                      }
                }) 
                })
    

    ajax上传文件

    • html文件
          用户名:<input type='text' name='username'>
          密码:<input type='text' name='password'>
          头像:<input type='file' name='touxiang'>
          <button id='sub'>上传</button>
    
          js部分
          $('$sub').click(function(){
                //ajax上传文件必须依赖于FormData对象
                var formdata = new FormData();
    
                var uname = $('[name="username"]').val();
                var pwd = $('[name="password"]').val();
                //获取浏览器上的文件数据方法:$('[name="touxiang"]')[0].files[0]
                var file_obj = $('[name="touxiang"]')[0].files[0];
                
                formdata.append('uname',uname)//后面取数据也是用request.POST.get('uname')
                formdata.append('pwd',pwd)
                formdata.append('csrfmiddlewaretoken','{{ csrf_token }}')
    
                //request.FILES
                formdata.append('touxiang',file_obj)
    
                $.ajax({
                      url:'',//如果路径为空,那么使用当前页面的路径,也就是往当前路径下进行提交
                      type:'post',
                      data:formdata,
                      //下面的两个参数的意思是,不要对数据进行任何的预处理和加工
                      processData:false,
                      contentType:false,
    
                      success:function(res){
                            console.log(res);
                      }
                })
          })
    
    • views文件
          def upload(request):
                if request.method == 'GET':
                      return render(request,'upload.html')
                else:
                      print(request.POST)
                      print(request.FILES)
                      file_obj = request.FILES.get('touxiang')
                      with open(file_obj.name,'wb') as f:
                            for i in file_obj:
                                  f.write(i)
                            //第二种写法
                            //默认一次返回大小为65536B,也就是64KB,最大2.5M
                            for chunk in file_obj.chunks():
                                  f.write(chunk)
                      return HttpResponse('ok')
    

    上传多文件 自行拓展 后续补充

    • html文件
          <input type='file' name='touxiang' multiple> //multiple为上传多个
    

    -------------------------------------------

    个性签名:代码过万,键盘敲烂!!!

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

  • 相关阅读:
    Java中两个Long对象如何比较是否相等
    微信小程序data数组push和remove问题
    微信小程序let和var以及const有什么区别
    小程序开发之弹出框
    Windows系统下如何卸载干净mysql
    jQuery序列化表单
    ssm框架使用详解&配置两个数据源
    nginx在一个服务器上配置两个项目,并通过两个不同的域名访问
    nginx跨域设置&文件上传大小限制
    Navicat11连接oracle数据库
  • 原文地址:https://www.cnblogs.com/weiweivip666/p/13388024.html
Copyright © 2011-2022 走看看