簡體   English   中英

AngularJS + Django Rest Framework + CORS(CSRF Coo​​kie未顯示在客戶端)

[英]AngularJS + Django Rest Framework + CORS ( CSRF Cookie not showing up in client )

我正在使用和Django Rest Framework + Django CORS Headers在AngularJS中開發一個1頁的應用程序。

我的問題是,當我聯系后端時,“csrftoken”cookie永遠不會出現在我的瀏覽器中。

例如:我正在使用帖子進行登錄。 我正確地獲得了“sessionid”cookie,但是“csrftoken”從未顯示出來,因此我無法從我的客戶端發出適當的帖子,因為我會因缺少csrf令牌而被拒絕。

  • 我已經分析了API的響應頭,而csrftoken則不然。
  • 我直接在其余的API瀏覽器中查看,它顯示在那里很好。
  • 只是要指出,我可以做我的第一個POST登錄,因為Django Rest Framework只強制CSRF用於經過身份驗證的用戶。 如果我嘗試重新登錄它將失敗,因為它出現了“sessionid”-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 = '';
    });
};

}]);

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

子域A上的AngularJS單頁Web應用程序,使用CORS和CSRF保護與子域B上的Django JSON(REST)API通信

由於我目前正在進行類似的設置,並且正在努力讓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 Coo​​kie。 例如,請參閱如何從一個Django項目運行多個網站

Django API應用程序 - 為了使CORS和CSRF保護工作,我需要在API后端執行以下操作。

在此應用程序的settings.py中(Django項目settings.py的擴展名):

  • 添加corsheaders應用程序和中間件以及CSRF中間件:
 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 =真

將ensure_csrf_cookie裝飾器添加到處理JSON API請求的視圖中:

 from django.views.decorators.csrf import ensure_csrf_cookie @ensure_csrf_cookie def myResource(request): ... 

用於AngularJS的Django App - AngularJS應用程序通過同一項目中的Django App提供。 這個Django應用程序設置為設置CSRF Coo​​kie。 然后,來自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 Coo​​kie。

下面我將展示如何使用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 } }); 

我希望這有幫助!!

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

如果您的視圖未呈現包含csrf_token模板標記的模板,則Django可能不會設置CSRF令牌cookie。 這在表單動態添加到頁面的情況下很常見。 為了解決這種情況,Django提供了一個視圖裝飾器來強制設置cookie:ensure_csrf_cookie()。

由於您的應用程序是單頁面應用程序,因此可以將ensure_csrf_cookie()添加到負責初始頁面加載的視圖中。

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

這是我的代碼的新片段:

后端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'

而已!

此解決方案的一個小更新。

從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

希望這有助於某人!

在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> 

然后在角度js應用程序,你只需要放置

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM