zoukankan      html  css  js  c++  java
  • vue与django CSRF认证(确切可行方案)

    vue与django交互参考  《django+vue+vue-resource+django-cors-headers实现前后端分离

    vue+django      django用的是vue  build后的 dist目录   启动用django共用一个端口,不存在跨域问题

    要实现csrf认证首先要了解django  CSRF原理

    CSRF跨域是不会自动生成csrftoken的(深坑,之前POST后端报错csrf not set 就是这个原因)

    post请求前必须先get一次产生token

    手动生成csrftoken

    1request.META["CSRF_COOKIE_USED"] = True
    2手动调用 csrf 中的 get_token(request) 或 rotate_token(request) 方法
    3html表单带{%csrf_token%} (适用于django render渲染的前端)

    在vivews.py设置

    # Create your views here.
    from django.shortcuts import  render,HttpResponse,redirect
    from blog.models import *
    from django.views.decorators.http import require_http_methods
    import json
    from django.core import serializers
    from django.http import JsonResponse
    from django.middleware.csrf import get_token ,rotate_token
    import simplejson
    @require_http_methods(["GET",'POST'])
    def add_book(request):
        response = {}
        try:
            if  request.method=='GET':
                get_token(request)  #或request.META["CSRF_COOKIE_USED"] = True   新加产生token
            if  request.method=='POST':
                req = simplejson.loads(request.body)  # json格式传过来的数
                Book.objects.create(
                    **req
                )
                # Book.objects.create(   #x-www-form-urlencoded传过来的数据
                #     **{"book_name":request.POST.get('book_name')},
                # )
                response['msg'] = 'success'
                response['error_num'] = 0
            # if request.method=='GET':
            #     # book = Book(book_name=request.GET.get('book_name'))
            #     # book.save()
            #     Book.objects.create(  # 方法二建议这种,直接将前端字典插入
            #         **{"book_name":request.GET.get('book_name')},
            #     )
            #     response['msg'] = 'success'
            #     response['error_num'] = 0
        except  Exception as e:
            response['msg'] = str(e)
            response['error_num'] = 1
        return JsonResponse(response)
    
    @require_http_methods(["GET",'POST'])
    def show_books(request):
        response = {}
        get_token(request)
        try:
            print(request.POST)
            print(request.body)
            books = Book.objects.filter()
            response['list']  = json.loads(serializers.serialize("json", books))
            response['msg'] = 'success'
            response['error_num'] = 0
        except  Exception as e:
            response['msg'] = str(e)
            response['error_num'] = 1
    
        return JsonResponse(response)     

    vue前端设定 main.js入口

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import VueResource from 'vue-resource'
    Vue.use(VueResource);
    Vue.config.productionTip = false;
    //Vue.http.options.xhr = { withCredentials: true };
    //Vue.http.options.emulateJSON = true;
    //Vue.http.interceptors.push(function(request, next) {//拦截器
    // 跨域携带cookie
    // request.credentials = true;
    //next()
    //});    //vue未build跨域使用的,跨域建议代理。更简便
    
    new Vue({
      el: '#app',
      router,
      components: { App },
      template: '<App/>'
    });

    Vue.http.options.xhr = { withCredentials: true }; 的用途就是允许跨域请求携带cookie做身份认证
    Vue.http.options.emulateJSON = true; 的作用是如果web服务器无法处理application/json的请求,你可以启用emulateJSON选项。启用该选项后请求会以application/x-www-form-urlencoded作为MIME type,就像普通的HTML表单一样
    拦截器主要是作用是可以在请求前和发送请求后做一些处理
    因为跨域请求是不会提供任何凭据的(cookie、HTTP认证及客户端SSL证明等),但是我们可以通过设置request.credentials = true;来表示允许

    components/submit.vue

    <template>
    <div id="tomato">
      <form @submit.prevent="submit">
          <div class="field">
              书名:
              <input type="text" v-model="book.book_name">
          </div>
    
          <input type="submit"
                 value="提交">
      </form>
      <button v-on:click="display">搜索</button>
      <table v-for="item in books">
        <tr>
          <td>书名:{{ item.fields.book_name}} && 添加时间:{{item.fields.add_time}}</td>
        </tr>
      </table>
    </div>
    </template>
    <script>
      export default {
        data (){
          return {
            books: [],
            book:{
              book_name:null,
          }
        }
        },
    //    mounted() {
    //      // GET /someUrl
    //      this.$http.get('http://127.0.0.1:8000/api/show_books').then(response => {
    //        this.books = response.data.list;
    //        console.log(this.books[0].fields.book_name);
    //        // get body data
    //        // this.someData = response.body;
    //
    //      }, response => {
    //        console.log("error");
    //      });
    //    },
        methods: {
            submit: function() {   //post函数
              var formData = JSON.stringify(this.book); // 这里才是你的表单数据
              console.log(formData);
              this.$http.get('http://127.0.0.1:8000/api/add_book'); //产生COOKIE 必须先get一次不然会报错csrf not set
              sleep(4000); //等级几秒等,不然可能获取不到cookie
              var DjangoCookie=getCookie('csrftoken');
              //发送过去的headers带上X-CSRFToken进行认证,值就是cookie csrftoken的值
              this.$http.post('http://127.0.0.1:8000/api/add_book',formData,{headers:{'X-CSRFToken':DjangoCookie}},{emulateJSON: true}).then((response) => {
                  // success callback
                  console.log(response.data);
              }, (response) => {
                   console.log("error");
                  // error callback
              });
    //          this.$http({       //此方法可以通过CSRF认证但是数据过不去,未深究
    //                    method:'POST',
    //                    url:'http://127.0.0.1:8000/api/add_book',
    //                    data:{'book_name':'lxs'},
    //                    headers: {"X-CSRFToken": DjangoCookie},
    //                    emulateJSON: true
    //                    }).then((response) => {
    //              // success callback
    //              console.log(response.data);
    //          }, (response) => {
    //               console.log("error");
    //              // error callback
    //          });
            },
            display() {
          // GET /someUrl URL为django接口地址
            this.$http.get('http://127.0.0.1:8000/api/show_books').then(response => {
              this.books = response.data.list;
              console.log(this.books[0].fields.book_name);
              // get body data
              // this.someData = response.body;
    
            }, response => {
              console.log("error");
            });
    //          this.$http({   //结果同上get
    //          method:'GET',
    //          url:'http://127.0.0.1:8000/api/show_books'}).then(response => {
    //          this.books = response.data.list;
    //          console.log(this.books[0].fields.book_name);
    //          // get body data
    //          // this.someData = response.body;
    //
    //        }, response => {
    //          console.log("error");
    //        });
        },
    
        },
      }
    function getCookie(name){  //获取cookie函数
        name = name + "=";
        var start = document.cookie.indexOf(name),
            value = null;
        if(start>-1){
            var end = document.cookie.indexOf(";",start);
            if(end == -1){
                end = document.cookie.length;
            }
            value = document.cookie.substring(start+name.length,end);
        }
        return value;
    }
    function sleep(numberMillis) {   //等待函数
        var now = new Date();
        var exitTime = now.getTime() + numberMillis;
        while (true) {
            now = new Date();
            if (now.getTime() > exitTime)
                return;
        }
    }
    </script>

     vue-resource 引入headers 除了局部引入,还可以在全局引入(在main,js引入后所有post请求都只需提交数据就行)

    import Vue from 'vue'
    import App from './App'
    import router from './router'
    import VueResource from 'vue-resource'
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    import store from './store/store'
    Vue.use(ElementUI);
    Vue.use(VueResource);
    Vue.config.productionTip = false;
    Vue.http.get('http://127.0.0.1:8000/api/add_book').then(response => {});
    let djangocookie=getCookie('csrftoken');
    Vue.http.headers.common['X-CSRFToken'] = djangocookie;//这里设置请求头
    router.beforeEach((to, from, next) => {
    if (to.path === '/login') {
        next()
      } else {
        if (!store.state.user ) {
          next({ path: '/login' })
        } else {
          next()
        }
      }
    });
    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: '<App/>'
    });
    
    function getCookie(name){  //获取cookie函数
        name = name + "=";
        let start = document.cookie.indexOf(name),
            value = null;
        if(start>-1){
            let end = document.cookie.indexOf(";",start);
            if(end === -1){
                end = document.cookie.length;
            }
            value = document.cookie.substring(start+name.length,end);
        }
        return value;
    }

    OK, 结束,完美收工,差点被百度的坑埋了。。。。相当。。。。。。。。。。。。。

    坚持到无能为力,拼搏到感动自己
  • 相关阅读:
    上传文件大小问题
    中检测到有潜在危险的 Request.Form 值
    Session
    C#浏览器中在线操作文档
    数据导入
    文件上传(插件版)和下载
    Leetcode练习(Python):递归类:面试题10- I. 斐波那契数列:写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下: F(0) = 0,&#160; &#160;F(1)&#160;= 1 F(N) = F(N
    Leetcode练习(Python):递归类:面试题07. 重建二叉树:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
    Leetcode练习(Python):递归类:面试题 16.11. 跳水板:你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。 返回的长度需要从小到大排列。
    Leetcode练习(Python):递归类:面试题 08.06. 汉诺塔问题:在经典汉诺塔问题中,有 3 根柱子及 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自上而下按升序依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。
  • 原文地址:https://www.cnblogs.com/linxizhifeng/p/8995077.html
Copyright © 2011-2022 走看看