AngularJS + Django Rest Framework + CORS (CSRF Cookie не отображается в клиенте)
Я разрабатываю одностраничное приложение в приложении AngularJS и Django Rest Framework + Django CORS Headers.
Моя проблема в том, что cookie "csrftoken" никогда не появляется в моем браузере, когда я связался с бэкэнд.
Например: я делаю логин, используя сообщение. Я получаю "sessionid" cookie правильно, но "csrftoken" никогда не появляется, и поэтому я не могу делать правильные сообщения от моего клиента, так как мне будет отказано из-за отсутствия токена csrf.
- Я проанализировал заголовки ответов из API, а csrftoken - не ther.
- Я посмотрел прямо в браузере остальных браузеров, и там он прекрасно выглядит.
- Как раз отметить, я могу сделать свой первый POST для входа, поскольку Django Rest Framework только заставляет CSRF для аутентифицированных пользователей. Если я попытаюсь переписать его, произойдет с момента появления "sessionid" -cookie.
- Я не заинтересован в обходе защиты CSRF, поскольку предлагают некоторые сообщения в stackoverflow.
Некоторые фрагменты кода с передней/внутренней стороны. Это незавершенные фрагменты, поэтому не зацикливайтесь на плохо написанном коде.
API-интерфейс Backend API LoginView
class LoginView(APIView):
renderer_classes = (JSONPRenderer, JSONRenderer)
def post(self, request, format=None):
serializer = LoginSerializer(data=request.DATA)
if serializer.is_valid():
userAuth = authenticate(username=serializer.data['username'], password=serializer.data['password'])
if userAuth:
if userAuth.is_active:
login(request, userAuth)
loggedInUser = AuthUserProfile.objects.get(pk=1)
serializer = UserProfileSerializer(loggedInUser)
user = [serializer.data, {'isLogged': True}]
else:
user = {'isLogged': False}
return Response(user, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Клиентская система управления доступом AngularJS
.controller('LoginCtrl', ['$scope', '$http', 'uService', '$rootScope', function(scope, $http, User, rootScope) {
scope.login = function() {
var config = {
method: 'POST',
withCredentials: true,
url: rootScope.apiURL+'/user/login/',
data : scope.loginForm
};
$http(config)
.success(function(data, status, headers, config) {
if (status == 200) {
console.log(data[0]); //Test code
// succefull login
User.isLogged = true;
User.username = data.username;
}
else {
console.log(data); //Test code
User.isLogged = false;
User.username = '';
}
})
.error(function(data, status, headers, config) {
console.log('Testing console error');
User.isLogged = false;
User.username = '';
});
};
}]);
Любой, у кого есть хорошие советы/идеи/примеры?
Ответы
Ответ 1
Итак, я нашел свое собственное решение, похоже, отлично работает.
Это новые фрагменты кода:
API-интерфейс Backend API LoginView (добавлен декоратор, заставляющий токен csrf добавляться в тело)
class LoginView(APIView):
renderer_classes = (JSONPRenderer, JSONRenderer)
@method_decorator(ensure_csrf_cookie)
def post(self, request, format=None):
c = {}
c.update(csrf(request))
serializer = LoginSerializer(data=request.DATA)
if serializer.is_valid():
userAuth = authenticate(username=serializer.data['username'], password=serializer.data['password'])
if userAuth:
if userAuth.is_active:
login(request, userAuth)
loggedInUser = AuthUserProfile.objects.get(pk=1)
serializer = UserProfileSerializer(loggedInUser)
user = [serializer.data, {'isLogged': True}]
else:
user = {'isLogged': False}
return Response(user, status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Сторона стороне AngularJS (добавить токен в заголовок запроса)
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
Файл настроек на стороне сервера (специально для django-cors-headers)
По умолчанию добавляются первые 5, но вам нужно добавить "X-CSRFToken", чтобы разрешить такой заголовок от клиента к API с помощью CORS, иначе сообщение будет отклонено.
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'X-CSRFToken'
)
Вот оно!
Ответ 2
Однопользовательское веб-приложение AngularJS на субдомене A, разговаривающее с API Jang JSON (REST) в поддомене B с использованием защиты CORS и CSRF
Поскольку я в настоящее время работаю над подобной настройкой и боролся за то, чтобы CORS правильно работал в сочетании с CSRF-защитой, я хотел поделиться своими собственными знаниями здесь.
Настройка - SPA и API находятся в разных поддоменах того же домена:
- AngularJS (1.2.14) Одностраничное веб-приложение на субдоме app.mydomain.com
- Приложение Django (1.6.2) реализует API JSON REST на поддомене api.mydomain.com
Приложение AngularJS подается через приложение Django в том же проекте, что и APP API Django, так что он устанавливает CSRF Cookie. См. Также, например, Как запустить несколько веб-сайтов из одного проекта Django
Django API App - для того, чтобы работать с CORS и CSRF, мне нужно было сделать следующее на бэкэнде API.
В settings.py для этого приложения (расширение проекта Django settings.py):
- Добавить приложение corsheaders и промежуточное ПО и промежуточное ПО CSRF:
INSTALLED_APPS = (
...
'corsheaders',
...
)
MIDDLEWARE_CLASSES = (
...
'django.middleware.csrf.CsrfViewMiddleware',
...
'corsheaders.middleware.CorsMiddleware',
)
Также см. заголовки Django CORS на GitHub
- Добавьте домен для SPA Webapp в CORS_ORIGIN_WHITELIST
CORS_ORIGIN_WHITELIST = [
...
'app.mydomain.com',
...
]
- Установите CORS_ALLOW_CREDENTIALS в значение True. Это важно, если вы этого не сделаете, cookie CSRF не будет отправлен с запросом
CORS_ALLOW_CREDENTIALS = True
Добавьте декоратор обеспечения_csrf_cookie к вашим представлениям, обрабатывающим запросы API JSON:
from django.views.decorators.csrf import ensure_csrf_cookie
@ensure_csrf_cookie
def myResource(request):
...
Приложение Django для AngularJS - приложение AngularJS подается через приложение Django в том же проекте. Это приложение Django настроено для установки CSRF Cookie. Затем токен CSRF из файла cookie используется для запросов к API (который, таким образом, выполняется как часть одного и того же проекта Django).
Обратите внимание, что почти все файлы, связанные с приложением AngularJS, являются только статическими файлами с точки зрения Django. Приложение Django должно обслуживать index.html, чтобы установить файл cookie.
В settings.py для этого приложения (снова расширение проекта Django settings.py), установите CSRF_COOKIE_DOMAIN таким образом, чтобы субдомены также могли их использовать:
CSRF_COOKIE_DOMAIN = ".mydomain.com"
В views.py мне нужно только отобразить файл AngularJS index.html, снова используя декоратор make_csrf_cookie:
from django.shortcuts import render
from django.views.decorators.csrf import ensure_csrf_cookie
# Create your views here.
@ensure_csrf_cookie
def index(request):
return render(request, 'index.html')
Отправка запросов в API с помощью AngularJS. В конфигурации приложения AngularJS установите следующие значения $httpProvider по умолчанию:
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
$httpProvider.defaults.withCredentials = true;
Опять же, обратите внимание на withCredentials, это гарантирует, что CSRF Cookie будет использоваться в запросе.
Ниже я покажу, как вы можете отправлять запросы на api, используя службу AngularJS $http и JQuery:
$http.post("http://api.mydomain.com/myresource", {
field1 : ...,
...
fieldN : ...
}, {
headers : {
"x-csrftoken" : $cookies.csrftoken
}
});
Также см. модуль ngCookies.
Использование JQuery (1.11.0):
$.ajax("http://api.mydomain.com/myresource", {
type: 'POST',
dataType : 'json',
beforeSend : function(jqXHR, settings) {
jqXHR.setRequestHeader("x-csrftoken", get_the_csrf_token_from_cookie());
},
cache : false,
contentType : "application/json; charset=UTF-8",
data : JSON.stringify({
field1 : ...,
...
fieldN : ...
}),
xhrFields: {
withCredentials: true
}
});
Надеюсь, это поможет!
Ответ 3
Непосредственно из документов https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax
Если ваше представление не отображает шаблон, содержащий csrf_token тег шаблона, Django может не устанавливать куки файл токена CSRF. Это обычно в тех случаях, когда формы динамически добавляются на страницу. к обратитесь к этому случаю, Django предоставляет декоратор, который заставляет настройка файла cookie: secure_csrf_cookie().
Поскольку ваше приложение является одностраничным, вы можете добавить ensure_csrf_cookie()
в представление, которое отвечает за загрузку начальной страницы.
Ответ 4
Небольшое обновление этого решения.
Так как AngularJS 1.2.10 вам нужно установить cookie CSRF для каждого типа запроса в клиенте:
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
$http.defaults.headers.put['X-CSRFToken'] = $cookies.csrftoken;
$http.defaults.headers['delete']['X-CSRFToken'] = $cookies.csrftoken;
Это вызвано следующим изменением, которое произошло между 1.2.9 и 1.2.10
https://github.com/cironunes/angular.js/commit/781287473bc2e8ee67078c05b76242124dd43376
Надеюсь, это поможет кому-то!
Ответ 5
После столь большого поиска я приземлился на это решение, и его работа формирует меня в локальной системе, а также на реальном сервере веб-фракций, это мое решение для пользователей Django, пожалуйста, зайдите в свою папку apache, расположенную в проекте то в корзине вы найдете
httpd.conf или конфигурацию вашего сервера для php или других пользователей (обычно находится в файле *.conf, таком как httpd.conf или apache.conf) или внутри .htaccess. то просто добавьте этот код
<IfModule mod_headers.c>
SetEnvIf Origin (.*) AccessControlAllowOrigin=$1
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header set Access-Control-Allow-Credentials true
</IfModule>
тогда в angular js app вам просто нужно разместить
angular.module('app', ['ngCookies'])
.config([
'$httpProvider',
'$interpolateProvider',
function($httpProvider, $interpolateProvider, $scope, $http) {
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
}]).
run([
'$http',
'$cookies',
function($http, $cookies) {
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
}]);
Он работал у меня на платформе Django Angularjs.
https://gist.github.com/mlynch/be92735ce4c547bd45f6