我正在使用和Django Rest Framework + Django CORS Headers在AngularJS中开发一个1页的应用程序。
我的问题是" csrftoken"当我联系后端时,cookie永远不会出现在我的浏览器中。
例如:我正在使用帖子进行登录。我得到了" sessionid" cookie正确,但" csrftoken"从来没有出现过,因此我无法从我的客户那里做适当的帖子,因为我因为缺少csrf令牌而被拒绝。
前/后端的一些代码段。这些是未完成的片段,所以不要挂在写得不好的代码上。
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)
.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 = '';
});
};
}]);
任何有任何好的提示/想法/例子的人?
答案 0 :(得分:35)
子域A上的AngularJS单页Web应用程序,使用CORS和CSRF保护与子域B上的Django JSON(REST)API进行通信
由于我目前正在进行类似的设置,并且正在努力让CORS与CSRF保护一起正常工作,我想在这里分享我自己的经验。
设置 - SPA和API都位于同一域的不同子域中:
AngularJS应用程序通过Django App在与Django API APP相同的项目中提供,以便设置CSRF Cookie。例如,请参阅How to run multiple websites from one Django project
Django API App - 为了使CORS和CSRF保护工作,我需要在API后端执行以下操作。
在此应用的settings.py中(Django项目settings.py的扩展名):
INSTALLED_APPS = ( ... 'corsheaders', ... ) MIDDLEWARE_CLASSES = ( ... 'django.middleware.csrf.CsrfViewMiddleware', ... 'corsheaders.middleware.CorsMiddleware', )
另见Django CORS headers on GitHub
CORS_ORIGIN_WHITELIST = [ ... 'app.mydomain.com', ... ]
CORS_ALLOW_CREDENTIALS = True
将ensure_csrf_cookie装饰器添加到处理JSON API请求的视图中:
from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def myResource(request): ...
用于AngularJS的Django应用程序 - AngularJS应用程序通过同一项目中的Django App提供。这个Django应用程序设置为设置CSRF Cookie。然后,来自cookie的CSRF令牌用于对API的请求(因此作为同一Django项目的一部分运行)。
请注意,几乎所有与AngularJS应用程序相关的文件都只是Django透视图中的静态文件。 Django App只需要提供index.html来设置cookie。
在此应用的settings.py中(同样是Django项目settings.py的扩展名),设置CSRF_COOKIE_DOMAIN,以便子域也可以使用它们:
CSRF_COOKIE_DOMAIN =" .mydomain.com"
在views.py中,我只需要再次使用ensure_csrf_cookie装饰器渲染AngularJS index.html文件:
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')
使用AngularJS向API发送请求 - 在AngularJS App配置中设置以下$ httpProvider默认值:
$httpProvider.defaults.xsrfCookieName = 'csrftoken'; $httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken'; $httpProvider.defaults.withCredentials = true;
再次注意withCredentials,这可以确保在请求中使用CSRF Cookie。
下面我将展示如何使用AngularJS $ http服务和JQuery向api发出请求:
$http.post("http://api.mydomain.com/myresource", { field1 : ..., ... fieldN : ... }, { headers : { "x-csrftoken" : $cookies.csrftoken } });
使用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 } });
我希望这会有所帮助!!
答案 1 :(得分:15)
直接来自文档https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax
如果您的视图未呈现包含csrf_token的模板 模板标签,Django可能不会设置CSRF令牌cookie。这是 在表单动态添加到页面的情况下很常见。至 解决这种情况,Django提供了一个强制的视图装饰器 设置cookie:ensure_csrf_cookie()。
由于您的应用程序是单页面应用程序,因此您可以将ensure_csrf_cookie()
添加到负责初始页面加载的视图中。
答案 2 :(得分:7)
所以我找到了自己的解决方案,似乎效果很好。
这是我的代码的新片段:
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)
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
CORS_ALLOW_HEADERS = (
'x-requested-with',
'content-type',
'accept',
'origin',
'authorization',
'X-CSRFToken'
)
多数民众赞成!
答案 3 :(得分:6)
此解决方案的一个小更新。
从AngularJS 1.2.10开始,您需要为客户端中的每个请求类型设置CSRF cookie:
$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
希望这有助于某人!
答案 4 :(得分:2)
经过如此多的搜索后,我登陆了这个解决方案,它的工作形成了我在本地系统和实时网络派系服务器上这是我对 Django 用户的解决方案请转到位于项目中的apache文件夹然后在bin中找到
<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;
}]);