angular + laravel restアプリケーション。データベースのビューを取得できます。新しいアイテムを追加しようとすると、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);
});
}
私のアプリケーションに使用するフィルターは次のとおりです。
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);
};
たぶん、あなたはこのソースコードを覗くことに興味があるでしょう sample Laravel + AngularJS project 。
ルーベンス・マリウッゾによる受け入れられた解決策は機能しますが、より良いと思う代替解決策を見つけたと思います。
この方法により、htmlスクリプトからanglejsアプリにデータを渡す必要がなくなり、懸念事項がより適切に分離されます。例えば。これにより、Laravel APPを単なるAPIとして使用できます。
私のソリューションには、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'
フィルターを使用したルートの保護
// 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.csrf
フィルター
// 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、no needを使用して、CSRFトークンをAngular httpヘッダー。
Laravel 5 with Angularこれを自動的に行います。
私のソリューションは痛みが少なく柔軟性が高いと思います。特にKarmaでアプリをテストすることを考えています。
まず、このコードをマスタービューに追加します
<meta name="csrf-token" content="{{ csrf_token() }}">
ルートを追加せずにcsrfトークンをhtmlコンテンツに保存しました。
これで、AngularJsアプリのすべてのリクエストをCSRFトークンで保護できます
/**
*
* 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ヘッダーを設定する必要があります。 Angularのヘッダーにcsrfトークンを追加しましょう
/*
* 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;
}]);
最後に、laravelの側でこの変更のための新しいフィルターが必要です。
Route::filter('csrfInHeader', function($route, $request) {
if (Session::token() !== (string) $request->header('X-CSRF-TOKEN') ) {
throw new Illuminate\Session\TokenMismatchException;
}
});
「csrfInHeader」フィルターは、すべてのhttpリクエストをangular appでチェックします。各リクエストにcsrfトークンを追加する必要はありません。さらに、Karmaでアプリをテストする場合、csrfを取得する努力はありませんテストのトークン.
としてそれを行う最も簡単な方法
Route::get('/getToken','Controller@getToken');
Webまたはapi.phpファイル内
コントローラー内
public function getToken(){
return csrf_token();
}
このコードを配置
In Angular app
$http.get("http://localhost:8000/getToken")
.then(function(response) {
alert(response.data)
});
Csrf_token()を取得する安全な方法