我正在使用AngularJS和Django Rest Framework + Django CORS Headers开发1页应用程序。
我的问题是,当我联系后端时,“ csrftoken” cookie永远不会显示在浏览器中。
例如:我正在使用帖子进行登录。我正确地获得了“ sessionid” cookie,但是“ csrftoken”却没有出现,因此我无法从客户端进行适当的发布,因为由于缺少csrf令牌而被拒绝了。
后端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 = ''; }); }; }]);
任何有好的技巧/想法/例子的人吗?
后端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”以允许使用CORS从客户端到API的此类标头,否则该帖子将被拒绝。
CORS_ALLOW_HEADERS = ( 'x-requested-with', 'content-type', 'accept', 'origin', 'authorization', 'X-CSRFToken' )
子域A上的AngularJS单页Web应用程序,使用CORS和CSRF保护与子域B上的Django JSON(REST)API通讯
由于我目前正在进行类似的设置,并且正在努力使CORS与CSRF保护结合使用,因此我想在这里分享自己的经验。
设置 -SPA和API都位于同一域的不同子域上:
Django API应用程序 -为了使CORS和CSRF保护正常工作,我需要在API后端执行以下操作。
在此应用程序的settings.py中(Django项目settings.py的扩展):
INSTALLED_APPS = ( ... 'corsheaders', ... ) MIDDLEWARE_CLASSES = ( ... 'django.middleware.csrf.CsrfViewMiddleware', ... 'corsheaders.middleware.CorsMiddleware', )
另请参阅GitHub上的Django CORS标头
将SPA Webapp的域添加到CORS_ORIGIN_WHITELIST
CORS_ORIGIN_WHITELIST = [ ... 'app.mydomain.com', ... ]
将CORS_ALLOW_CREDENTIALS设置为True。这很重要,如果您不这样做,则不会随请求一起发送CSRF Cookie CORS_ALLOW_CREDENTIALS =真
将suresure_csrf_cookie装饰器添加到处理JSON API请求的视图中:
from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def myResource(request): ...
AngularJS的Django应用程序 -AngularJS应用程序通过同一项目中的Django应用程序提供。此Django应用程序已设置为设置CSRF Cookie。Cookie中的CSRF令牌随后用于对API的请求(因此,该API作为同一Django项目的一部分运行)。
请注意,从Django角度来看,几乎与AngularJS应用程序相关的所有文件都是静态文件。Django应用程序仅需要提供index.html即可设置cookie。
在此应用程序的settings.py中(再次是Django项目settings.py的扩展),设置CSRF_COOKIE_DOMAIN,以便子域也可以使用它们:
CSRF_COOKIE_DOMAIN =“ .mydomain.com”
在views.py中,我只需要渲染一次AngularJS index.html文件,再次使用guarantee_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')
使用AngularJS向API发送请求 -在AngularJS应用配置中,设置以下$ 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 } });
另请参见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 } });
我希望这有帮助!!