首页 文章

AngularJS Django Rest Framework CORS(CSRF Cookie未显示在客户端)

提问于
浏览
33

我正在使用和Django Rest Framework Django CORS Headers在AngularJS中开发一个1页的应用程序 .

我的问题是,当我联系后端时,“csrftoken”cookie永远不会出现在我的浏览器中 .

例如:我正在使用帖子进行登录 . 我正确地获得了“sessionid”cookie,但是“csrftoken”从未出现,因此我无法从我的客户端发出适当的帖子,因为我因为缺少csrf令牌而被拒绝 .

  • 我已经分析了API的响应头,而csrftoken则不然 .

  • 我直接在其余的API浏览器中查看,它显示在那里很好 .

  • 只是要指出,我可以做我的第一个POST登录,因为Django Rest Framework只强制CSRF用于经过身份验证的用户 . 如果我尝试重新登录它将会失败,因为它出现了.2702917_ -cookie .

  • 我没有绕过CSRF保护,因为stackoverflow上的一些帖子表明 .

前/后端的一些代码片段 . 这些是未完成的片段,所以不要挂在写得不好的代码上 .

后端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 = '';
    });
};

}]);

谁有任何好的提示/想法/例子?

5 回答

  • 7

    AngularJS Single Page Web Application on Sub-domain A, talking to a Django JSON (REST) API on Sub-domain B using CORS and CSRF protection

    由于我目前正在进行类似的设置,并且正在努力让CORS与CSRF保护相结合,我想在这里分享我自己的经验 .

    设置 - SPA和API都位于同一域的不同子域中:

    • AngularJS(1.2.14)子域app.mydomain.com上的单页Web应用程序

    • Django App(1.6.2)在子域api.mydomain.com上实现JSON REST API

    AngularJS应用程序通过Django App在与Django API APP相同的项目中提供,以便设置CSRF Cookie . 例如,参见How to run multiple websites from one Django project

    Django API应用程序 - 为了使CORS和CSRF保护工作,我需要在API后端执行以下操作 .

    在此应用程序的settings.py中(Django项目settings.py的扩展名):

    • 添加corsheaders应用和中间件以及CSRF中间件:

    INSTALLED_APPS =(
    ...
    'corsheaders',
    ...

    MIDDLEWARE_CLASSES =(
    ...
    'django.middleware.csrf.CsrfViewMiddleware',
    ...
    'corsheaders.middleware.CorsMiddleware',

    另见Django CORS headers on GitHub

    • 将SPA Webapp的域添加到CORS_ORIGIN_WHITELIST

    CORS_ORIGIN_WHITELIST = [
    ...
    'app.mydomain.com',
    ...
    ]

    • 将CORS_ALLOW_CREDENTIALS设置为True . 这很重要,如果您不这样做,将不会随请求一起发送CSRF cookie

    CORS_ALLOW_CREDENTIALS = True

    将ensure_csrf_cookie装饰器添加到处理JSON API请求的视图中:

    来自django.views.decorators.csrf import ensure_csrf_cookie

    @ensure_csrf_cookie
    def myResource(请求):
    ...

    用于AngularJS的Django App - 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文件:

    来自django.shortcuts导入渲染
    来自django.views.decorators.csrf import ensure_csrf_cookie

    #在这里创建你的观点 .
    @ensure_csrf_cookie
    def索引(请求):
    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
    }
    });

    另见ngCookies module .

    使用JQuery(1.11.0):

    $ .ajax(“http://api.mydomain.com/myresource”,{
    类型:'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
    }
    });

    我希望这有帮助!!

  • 6

    直接来自文档https://docs.djangoproject.com/en/1.9/ref/csrf/#ajax

    如果您的视图未呈现包含csrf_token模板标记的模板,则Django可能不会设置CSRF令牌cookie . 这在表单动态添加到页面的情况下很常见 . 为了解决这种情况,Django提供了一个视图装饰器来强制设置cookie:ensure_csrf_cookie() .

    由于您的应用程序是单页面应用程序,因此可以将 ensure_csrf_cookie() 添加到负责初始页面加载的视图中 .

  • 15

    所以我找到了自己的解决方案,似乎工作得很好 .

    这是我的代码的新片段:

    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”以允许使用CORS从客户端到API的此类标头,否则将拒绝该帖子 .

    CORS_ALLOW_HEADERS = (
    'x-requested-with',
    'content-type',
    'accept',
    'origin',
    'authorization',
    'X-CSRFToken'
    

    而已!

  • 2

    此解决方案的一个小更新 .

    从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

    希望这有助于某人!

  • 35

    在So Much Search之后我登陆了这个解决方案,它的工作形成了我在本地系统和实时网络派系服务器这是我的解决方案 Django 用户请转到位于项目中的apache文件夹然后在bin中找到

    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

相关问题