Django React CSRF问题

时间:2019-01-04 21:30:48

标签: django reactjs django-cors-headers

使用Django作为后端并使用React作为前端来构建我的第一个应用程序。

在本地,我都分别在端口8000和3000上运行。

我在网上找到了一小段代码,以帮助我测试我的CSRF和CORS策略是否设置正确:

const API_HOST = 'http://localhost:8000';

let _csrfToken = null;

async function getCsrfToken() {
  if (_csrfToken === null) {
    const response = await fetch(`${API_HOST}/csrf/`, {
      credentials: 'include',
    });
    const data = await response.json();
    _csrfToken = data.csrfToken;
  }
  return _csrfToken;
}

async function testRequest(method) {
  const response = await fetch(`${API_HOST}/ping/`, {
    method: method,
    headers: (
      method === 'POST'
        ? {'X-CSRFToken': await getCsrfToken()}
        : {}
    ),
    credentials: 'include',
  });
  const data = await response.json();
  return data.result;
}


class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      testGet: 'KO',
      testPost: 'KO',
    };
  }

  async componentDidMount() {
    this.setState({
      testGet: await testRequest('GET'),
      testPost: await testRequest('POST'),
    });
  }

  render() {
    return (
      <div>
        <p>Test GET request: {this.state.testGet}</p>
        <p>Test POST request: {this.state.testPost}</p>
      </div>
    );
  }
}

export default App;

编辑以澄清:远程GET请求通过,只有POST失败

当我在本地运行此代码时,我得到正确的响应,即,当响应恢复有效时,“ KO”变为“ OK”。

这仅在我的机器上有效。如果尝试从网络中的任何其他计算机访问它,则会出现以下错误:

403禁止

Django的调试原因是“未设置CSRF cookie”。

但是,在控制台中,我可以看到标头确实在发送X-CSRFToken。

我有一个后端的“实时”版本,我也尝试使用该版本,获得与本地相同的结果。

只有在两台开发服务器都位于自己的计算机上尝试才能成功通过测试。

Django设置:

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = ['localhost:3000', 'My_Public_Ip:3000']

我怀疑我的问题在该白名单中的某处,但现在我茫然地发现了问题所在。

如果有人可以帮助我了解正在发生的事情,如果他们没有答案,则可能会触发一个“啊哈”时刻。

2 个答案:

答案 0 :(得分:2)

您是否尝试过从实际cookie中获取CSRF令牌,而不是向服务器发出请求? 因为实际上您现在要做的就是每次尝试获取任何东西时都获得CSRF令牌。

在JavaScript中尝试以下操作:

import Cookies from 'js-cookie;

async function testRequest(method) {
    const headers = {};
    const csrftoken = Cookies.get('csrftoken'); // or the value from settings.CSRF_COOKIE_NAME
    if (csrftoken) {
        headers['X-CSRFTOKEN'] = csrftoken;
    }
    const response = await fetch(`${API_HOST}/ping/`, {
        method,
        headers,
        credentials: 'include',
    });
    const data = await response.json();
    return data.result;
}

答案 1 :(得分:1)

除了@tgdn建议从cookie获取令牌之外,我还建议您检查CSRF-和Session-cookie的SameSite策略设置,将其设置为{{ 1}}或Strict还将禁止在跨域请求中发送cookie(这可能会导致会话丢失/被注销等)。