如何使用Laravel API在AngularJS表单中发送csrf_token()?

我正在尝试构build一个angular度+ laravelrest应用程序。 我可以得到我的数据库的意见。 当我尝试添加新项目。 我得到500 error告诉我不匹配csrf令牌。 我的表单布局是:

 <form class="form-horizontal" ng-submit="addItem()"> <input type="text" ng-model="itemEntry" placeholder="Type and hit Enter to add item"> </form> 

这是我如何尝试添加项目数据库:

 $scope.addItem = function(CSRF_TOKEN) { $http.post('/shop', { text: $scope.itemEntry, csrf_token: CSRF_TOKEN} ).success(function(data, status) { if(data) { var last = _.last($scope.items); _token = CSRF_TOKEN; $scope.items.push({text: $scope.itemEntry, bought: false, id: (last.id + 1) }); $scope.itemEntry = ''; console.log($scope.items); } else { console.log('There was a problem. Status: ' + status + '; Data: ' + data); } }).error(function(data, status) { console.log('status: ' + status); }); } 

这是我用于我的应用程序的filter:

 Route::filter('csrf', function() { if (Session::token() != Input::get('_token')) { throw new Illuminate\Session\TokenMismatchException; } }); 

在我的刀片视图中,我使用这个工具:

 <input type="hidden" name="_token" value="{{ csrf_token() }}" /> 

当我使用html表单时,如何发送csrf_token?

谢谢

编辑1:添加标题来发布这样的请求不会给出错误。

  $http({ method : 'POST', url : '/shop', data : $scope.itemEntry, // pass in data as strings headers : { 'Content-Type': 'application/x-www-form-urlencoded' } }); 

一个选项是将CSRF令牌作为常量注入。 在您的标签中添加以下内容:

 <script> angular.module("app").constant("CSRF_TOKEN", '{{ csrf_token() }}'); </script> 

然后在你的模块方法,它可以在需要时注入。

 app.factory("FooService", function($http, CSRF_TOKEN) { console.log(CSRF_TOKEN); }; 

也许您会对这个Laravel + AngularJS项目样例的源代码感兴趣。

Rubens Mariuzzo接受的解决scheme是可行的,但是我认为我find了一个我认为更好的替代解决scheme。

通过这种方式,您不必将html脚本中的数据传递到您的angularjs应用程序,并且可以更好地分离关注点。 例如,这可以让你把你的Laravel APP作为一个API。

我的解决scheme涉及通过api请求获取CSRF令牌并将此值设置为常量。

此外,在需要的时候,不要注入CSRF令牌,而是将令牌设置为默认头,服务器在任何API http请求时都会检查该头。

例子显示了laravel,但是任何严肃的框架都应该能够提供类似的东西。

LARAVEL的CSRF路线:

 // Returns the csrf token for the current visitor's session. Route::get('api/csrf', function() { return Session::token(); }); 

使用before => 'api.csrf'filter保护路由

 // Before making the declared routes available, run them through the api.csrf filter Route::group(array('prefix' => 'api/v1', 'before' => 'api.csrf'), function() { Route::resource('test1', 'Api\V1\Test1Controller'); Route::resource('test2', 'Api\V1\Test2Controller'); }); 

api.csrffilter

 // If the session token is not the same as the the request header X-Csrf-Token, then return a 400 error. Route::filter('api.csrf', function($route, $request) { if (Session::token() != $request->header('X-Csrf-Token') ) { return Response::json('CSRF does not match', 400); } }); 

AngularJS的东西把这个在app.js中:

阻止版本:

 var xhReq = new XMLHttpRequest(); xhReq.open("GET", "//" + window.location.hostname + "/api/csrf", false); xhReq.send(null); app.constant("CSRF_TOKEN", xhReq.responseText); app.run(['$http', 'CSRF_TOKEN', function($http, CSRF_TOKEN) { $http.defaults.headers.common['X-Csrf-Token'] = CSRF_TOKEN; }]); 

非阻塞版本

 var xhReq = new XMLHttpRequest(); xhReq.open("GET", "//" + window.location.hostname + "/api/csrf", true); xhReq.onload = function(e) { if (xhReq.readyState === 4) { if (xhReq.status === 200) { app.constant("CSRF_TOKEN", xhReq.responseText); app.run(['$http', 'CSRF_TOKEN', function($http, CSRF_TOKEN) { $http.defaults.headers.common['X-Csrf-Token'] = CSRF_TOKEN; }]); } } }; xhReq.send(null); 

现在,CSRF_TOKEN常量被作为头部注入来自AngularJS应用程序的所有http请求中,并且所有API路由都受到保护。

如果您使用Laravel 5,则不需要将CSRF令牌添加到Angular http头中。

与Angular Laravel 5自动为你做这个。

http://laravel.com/docs/5.1/routing#csrf-x-xsrf-token

我认为我的解决scheme不那么痛苦,更加灵活,特别是它认为testing你的应用程序在噶玛。

首先添加这个代码您的主视图

  <meta name="csrf-token" content="{{ csrf_token() }}"> 

我们已经将csrf标记保存到html内容中,而不添加路由。

现在我们通过CSRF令牌来保护AngularJs应用程序的所有请求

 /** * * when it thinks testing your app unit test with Karma, * this solution was better than getting token via AJAX. * Because low-level Ajax request correctly doesn't work on Karma * * Helper idea to me : * http://stackoverflow.com/questions/14734243/rails-csrf-protection-angular-js-protect-from-forgery-makes-me-to-log-out-on/15761835#15761835 * */ var csrftoken = (function() { // not need Jquery for doing that var metas = window.document.getElementsByTagName('meta'); // finding one has csrf token for(var i=0 ; i < metas.length ; i++) { if ( metas[i].name === "csrf-token") { return metas[i].content; } } })(); // adding constant into our app yourAngularApp.constant('CSRF_TOKEN', csrftoken); 

我们需要为Angular设置默认的http头。 让我们将我们的csrf标记添加到Angular的标题

 /* * App Configs */ blog.config(['$httpProvider', 'CSRF_TOKEN', function($httpProvider, CSRF_TOKEN) { /** * adds CSRF token to header */ $httpProvider.defaults.headers.common['X-CSRF-TOKEN'] = CSRF_TOKEN; }]); 

最后,我们不得不需要新的filter来对laravel这个变化

 Route::filter('csrfInHeader', function($route, $request) { if (Session::token() !== (string) $request->header('X-CSRF-TOKEN') ) { throw new Illuminate\Session\TokenMismatchException; } }); 

“csrfInHeader”filter将检查angular应用程序的所有HTTP请求。 您不需要为每个请求添加csrf标记。 此外,如果您通过Karmatesting您的应用程序,您将不会努力获取csrf标记进行testing。