Angular2和Django:CSRF令牌头痛

时间:2016-09-10 23:10:03

标签: python django angular cors csrf

我遇到的问题

  • 我正在从 Angular2 客户端向我的 Django (v1.9)后端(在本地主机,不同端口上)发出Ajax POST请求。我还没有使用Django REST框架,我只是在没有任何附件的情况下将Djon转储到Django中。
  • 我的服务器已经发出 csrf令牌,我手动将其发送回HTTP标头(我可以在拨打电话时看到它)。
  • 但是,我仍然从django收到错误:禁止(未设置CSRF cookie。)
  • 我已经阅读了很多其他主题,并尝试了一些方法,但仍然无法让Django接受CSRF令牌。

客户端代码:

private _editUserUri = "http://127.0.0.1:8000/search/edit/user/";

constructor(private _http: Http){}

getCookie(name) {
    let value = "; " + document.cookie;
    let parts = value.split("; " + name + "=");
    if (parts.length == 2) 
      return parts.pop().split(";").shift();
}

validateData(userdata) {
    return true;
}

editUser(userdata) {

    console.log("UserService: createUser function called");
    console.log(JSON.stringify(userdata));

    if(this.validateData(userdata)) {

        let headers = new Headers({
            'Content-Type': 'application/json',
            'X-CSRFToken': this.getCookie('csrftoken')
        });

        let options = new RequestOptions({ headers: headers });

        return this._http
            .post(
                this._editUserUri,
                JSON.stringify(userdata),
                options)
            .map(res => {
                console.log(res.json());
                return res.json();
            })
    }

}

标题中的csrf标记的屏幕截图(x-csrftoken)。这正是Django的预期sourceScreenshot

我尝试/考虑的内容

  • 我想也许csrf令牌已经过时了。我试图创造一个新的,但我还没有设法让Django给我一个新的。我尝试过使用@ensure_csrf_cookie装饰器,但仍然没有。如果我在今天早上放置的cookie中有一个csrf令牌,我是否希望它被一个新的最新版本取代?

  • 另一个想法是标题名称(x-csrftoken)是小写的。 Django指定标题名称应为以下内容: X-CSRFToken 。但是,通过在线阅读,标题通常应该区分大小写。在任何情况下,Angular2都会自动将标题名称转换为小写。

  • 我尝试了一些我在Stack Overflow上发现的其他解决方案(example),但没有运气。

  • 我认为这可能与CORS有关,但第一个OPTIONS请求从我的Django服务器返回200。这个飞行前请求也不需要在其标题中包含csrf令牌,是吗? (原谅我的无知)

  • 我很确定我的设置很好。我有&#d; django.middleware.csrf.CsrfViewMiddleware'在MIDDLEWARE_CLASSES中, CSRF_COOKIE_SECURE = False CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = True

如果有人可以提供帮助,我会非常感激!

尼克

1 个答案:

答案 0 :(得分:2)

我认为问题在于您的请求只有CSRF令牌标头,而不是Cookie(请参阅double submit针对CSRF的缓解,您要发送的标头应与Cookie进行比较)。

我不太清楚究竟发生了什么。如果你详细说明Angular应用程序的下载地点以及如何从Django获取CSRF cookie,这是一个不同的起源,我可以编辑这个答案来帮助更多。我不能得到的是,如果Angular应用程序是从端口A下载的,那么它在端口B上有Django的CSRF cookie。

修改

你正在使用CORS吗?我认为你需要在jQuery请求中withCredentials,以便随请求一起发送csrf cookie:

xhrFields: {
    withCredentials: true
}

然后Django需要发送Access-Control-Allow-Credentials: true