如何在'Axios.interceptors.request`的配置中获取Cookies'`csrftoken`?

时间:2018-03-16 02:57:26

标签: javascript axios

如何在csrftoken的配置中获取Cookie Axios.interceptors.request

Axios.interceptors.request.use(
  config => {

    if (
      config.method === "post" ||
      config.method === "put" ||
      config.method === "delete"||
      config.method === "get"
    ) {

    }


    if (Cookies.get('token')!==undefined) {   
      config.headers['Authorization']= 'Token '+Cookies.get('token');
    }
    // there I try to get the `csrftoken` in the Cookies, but I can not get.
    if (Cookies.get('csrftoken')!==undefined) {   

      config.headers['x-csrftoken']= Cookies.get('csrftoken');  // 'CSRFToken'
    }

    return config;
  },
  error => {  
    return Promise.reject(error.data.error.message);
  }
);

Axios.interceptors.request的配置中,我无法获取Cookie csrftokenCookies.get('csrftoken')

我的AxiosConfig代码如下:

AxiosConfig:{
    baseURL: 'http://10.10.10.105:8001/',

    responseType: "json",
    withCredentials: true,  // there will send the Cookie (with it there are: sessionid, csrftoken)

    xsrfCookieName: 'csrftoken',  // default: XSRF-TOKEN
    xsrfHeaderName: 'x-csrftoken',   // default: X-XSRF-TOKEN
    headers: {
      "Content-Type": "application/json;charset=utf-8"
    }
  }

修改-1

Cookie中有csrftoken

enter image description here

修改-2

在Cookie中,也没有csrftoken

enter image description here

修改-3

如果我在控制台中获得document.cookie,我将获得"": ```

  

的document.cookie
  < “”   ```

修改-4

在我的Django后端,settings.py

INSTALLED_APPS:

...
'corsheaders', 

'rest_framework',
'rest_framework.authtoken',
'rest_framework_docs',   
'rest_auth',
'allauth',
'allauth.account',
'allauth.socialaccount',
'rest_auth.registration',
...

我不确定rest_authallauth是否会影响csrftoken

2 个答案:

答案 0 :(得分:1)

首先,请务必确保Cookie未标记为httpOnly

如果是,您的javascript代码将无法读取/修改其内容。

您可以在浏览器中查看Cookie标签,看看它是否可读。

在您的情况下,django不应将标记设置为httpOnly,因为docs描述了如何直接从javascript读取值饼干。

我可以通过经验指出一些事情:

  • 当您在拦截器中收到数据时,配置对象可能尚未填充数据。因此,设置config.headers = ...;可能会触发错误。

请务必写下:

config.headers = config.headers || {}; 

在设置headers之前,所以没有' config.headers未定义' 将被触发。

  • 或者直接阅读Cookie,根据默认程序将csrf值存储在隐藏的input中。

您可以执行以下操作(语法可能不正确):

<input type="hidden"
   name="csrftoken"
   value="{% csrf_token %}"/>
</div>

然后在拦截器中发送令牌:

config.headers['x-csrftoken'] = document.querySelector('input[name="csrftoken"]').value;

在这种情况下,由于您不需要阅读Cookie,因此将其设置为httpOnly将是巨大的优势

答案 1 :(得分:0)

Axios具有order of precedence来配置设置,因此设置可能被其他代码覆盖。

例如,在 Chrome 浏览器中,您可以打开“开发工具”窗格,单击“应用程序”选项卡,然后在左侧单击“ Cookie”以查看这些以确保正确存在:

enter image description here

如果您有一个定义request interceptor头的Axios XSRF-TOKEN,它将被以下内容覆盖:

axios.post(route('logout'), undefined, {
    headers: {
        'XSRF-TOKEN': 'bad',
    },
});

如果您有一个文件,例如在许多Laravel / Vue项目中称为bootstrap.jsaxios.js的文件,它声明了全局配置设置,则该设置可能会被拦截器覆盖。

例如:

// document head
<meta name="csrf-token" content="{{ csrf_token() }}">

...

// axios.js or bootstrap.js (imported in SPA app's main.js file)
window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

const token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    // an interceptor would overwrite this due to right-to-left precedence
    window.axios.defaults.headers.common['XSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

最后一个示例非常重要,因为它将用于调用内部API。如果您要调用利用CORS的外部API(例如Google),则它们可能需要特定的标头,而其他标头可能会引发错误。

要临时覆盖标头,可以在调用外部API的地方使用这种模式:

// temporarily wipe 'XSRF-TOKEN' header for Google CORS
const instance = axios.create();

instance.defaults.headers.common = {};
instance.defaults.headers.common.accept = 'application/json';

const { data } = await instance.get('https://www.external.com/foobars');

这也会覆盖拦截器,因为设计上的instance优先于全局默认值。

这是我使用的request interceptor

import Cookies from 'js-cookie';

/**
 * Request interceptor: for each request to the server,
 * attach the CSRF token if it exists.
 *
 */
axios.interceptors.request.use(async (request) => {
    try {
        const csrf = Cookies.get('XSRF-TOKEN');
        request.withCredentials = true;

        if (csrf) {
            request.headers.common['XSRF-TOKEN'] = csrf;
        }

        return request;
    } catch (err) {
        throw new Error(`axios# Problem with request during pre-flight phase: ${err}.`);
    }
});

由于CSRF要求可以通过JavaScript进行访问,因此必须不能httpOnly,因此您可以使用{ {1}},但返回以分号分隔的键/值对字符串,因此您可以通过创建提取CSRF的函数来锻炼头脑。

js-cookie

奖金阅读: