vue與django CSRF認證(確切可行方案)

vue與django交互參考  《django+vue+vue-resource+django-cors-headers實現先後端分離css

vue+django      django用的是vue  build後的 dist目錄   啓動用django共用一個端口,不存在跨域問題html

要實現csrf認證首先要了解django  CSRF原理前端

CSRF跨域是不會自動生成csrftoken的(深坑,以前POST後端報錯csrf not set 就是這個緣由)vue

post請求前必須先get一次產生tokenweb

手動生成csrftokendjango

1request.META["CSRF_COOKIE_USED"] = True
2手動調用 csrf 中的 get_token(request) 或 rotate_token(request) 方法
3html表單帶{%csrf_token%} (適用於django render渲染的前端)element-ui

在vivews.py設置json

# 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;來表示容許api

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, 結束,完美收工,差點被百度的坑埋了。。。。至關。。。。。。。。。。。。。

相關文章
相關標籤/搜索