Значок Django csrf + Angularjs

У меня есть django, работающий на сервере apache с использованием mod_wsgi, а также приложение angularjs, которое выполняется непосредственно apache, а не django. Я хотел бы сделать POST-вызовы на сервер django (работает rest_framework), но у меня возникают проблемы с токеном csrf.

Можно ли установить маркер с сервера, не помещая {% csrf token %} в качестве части шаблона (поскольку эти страницы не проходят через django)?

  • Я хотел бы иметь возможность получить токен csrf через запрос GET в качестве файла cookie.
  • Я хотел бы иметь возможность затем отправлять POST-запросы на сервер django с использованием значения cookie файла маркера csrf.

Ответ 1

Django и AngularJS уже имеют поддержку CSRF, ваша часть довольно проста.

Во-первых, вам нужно включить CSRF в Django, я полагаю, вы уже сделали это, если нет, следуйте за Django doc https://docs.djangoproject.com/en/1.5/ref/contrib/csrf/#ajax.

Теперь Django установит cookie с именем csrftoken в первом запросе GET и ожидает пользовательский заголовок HTTP X-CSRFToken в последующих запросах POST/PUT/DELETE.

Для Angular он ожидает файл cookie с именем XSRF-TOKEN и будет делать запросы POST/PUT/DELETE с заголовком X-XSRF-TOKEN, поэтому вам нужно немного подкорректировать, чтобы оба они были друг с другом:

$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';

Добавьте выше две строки где-то в вашем js-коде, блок module.config() - это хорошее место для этого.

Что это.

ПРИМЕЧАНИЕ. Это для angular 1.1.5, более старым версиям может потребоваться другой подход.

Обновление:

Так как приложение angular не обслуживается django, чтобы позволить cookie быть установленным, приложение angular должно сначала выполнить запрос GET для django.

Ответ 2

var foo = angular.module('foo', ['bar']);

foo.config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.xsrfCookieName = 'csrftoken';
    $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);

И все модули и контроллеры, в которых используется $http, будут отправлять запросы с помощью токена csrf.

Ответ 3

После поиска, что сработало для меня, был этот пост со следующим кодом:

angular.module( '[your module name]',
    ... [some dependencies] ...
    'ngCookies',
    ... [other dependencies] ...
)
.run( function run( $http, $cookies ){

    // For CSRF token compatibility with Django
    $http.defaults.headers.post['X-CSRFToken'] = $cookies.get('csrftoken');
})

Это, конечно, после получения файла cookie через запрос GET с сервера django.

Я также рассмотрел некоторые другие ответы здесь, в том числе Е. Люн, но не смог найти ничего в официальных документах, определяющих изменения параметров по умолчанию для xsrf на $httpProvider, кроме этот запрос на растяжение, который не работал у меня во время написания этого сообщения.

Ответ 4

Я создал приложение Django для моего приложения AngularJS, в том же проекте Django, что и приложение Django для моего (REST) ​​API, которое обслуживает только файл index.html(который является только sym.link). Таким образом, CSRF Cookie устанавливается без дополнительного запроса GET.

Пожалуйста, см. мой ответ здесь Единичное веб-приложение AngularJS на субдомене. Разговор с API Jango JSON (REST) ​​в поддомене B с использованием защиты CORS и CSRF.

Ответ 5

Если у вас есть файлы cookie, запрещающие доступ к javascript, вам необходимо сделать следующее. В своем шаблоне перед созданием приложения django добавьте следующее:

<script>
    window.csrf_token = "{{ csrf_token }}";
</script>

В вашем приложении angular добавьте следующее:

angularApp.config(["$httpProvider", function($httpProvider) {
    $httpProvider.defaults.headers.common["X-CSRFToken"] = window.csrf_token;
}]);

Как минимум через Django 1.9, токен CSRF не изменяется с каждым запросом. Он изменяется только при входе пользователя в систему. Если вы используете одностраничное приложение angular, вам нужно убедиться, что вы reset токен при входе/выходе из системы, и это должно работать нормально.

ПРИМЕЧАНИЕ. Это не работает в Django 1.10 или новее из-за изменения токена CSRF для каждого запроса. См. Пропустить токен CSRF для Django до angular с помощью CSRF_COOKIE_HTTPONLY