yts*_*jam 23 csrf-protection laravel angularjs
我正在尝试构建一个角度+ laravel休息应用程序.我可以获得我的数据库的视图.当我尝试添加新项目时.我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>
Run Code Online (Sandbox Code Playgroud)
这是我尝试将项添加到数据库的方式:
$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);
});
}
Run Code Online (Sandbox Code Playgroud)
这是我用于我的应用程序的过滤器:
Route::filter('csrf', function()
{
if (Session::token() != Input::get('_token'))
{
throw new Illuminate\Session\TokenMismatchException;
}
});
Run Code Online (Sandbox Code Playgroud)
在我的刀片视图中,我使用它并且它有效:
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
Run Code Online (Sandbox Code Playgroud)
当我使用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' }
});
Run Code Online (Sandbox Code Playgroud)
Rub*_*zzo 29
一个选项是将CSRF令牌注入为常量.在头标记中附加以下内容:
<script>
angular.module("app").constant("CSRF_TOKEN", '{{ csrf_token() }}');
</script>
Run Code Online (Sandbox Code Playgroud)
然后在您的模块方法中,可以在需要时注入它.
app.factory("FooService", function($http, CSRF_TOKEN) {
console.log(CSRF_TOKEN);
};
Run Code Online (Sandbox Code Playgroud)
也许您会对查看此示例Laravel + AngularJS项目的源代码感兴趣.
Gra*_*avy 23
Rubens Mariuzzo所接受的解决方案是有效的,但我认为我找到了一种替代解决方案,我认为这种解决方案更好.
这样您就不必将数据从html脚本传递到angularjs应用程序中,并且可以更好地分离关注点.例如,这允许您将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();
});
Run Code Online (Sandbox Code Playgroud)
使用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');
});
Run Code Online (Sandbox Code Playgroud)
该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);
}
});
Run Code Online (Sandbox Code Playgroud)
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;
}]);
Run Code Online (Sandbox Code Playgroud)
非阻止版本
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);
Run Code Online (Sandbox Code Playgroud)
现在,CSRF_TOKEN常量作为来自AngularJS应用程序的所有http请求中的标头注入,并且所有API路由都受到保护.
Mod*_*der 22
如果您使用Laravel 5,则无需向Angular http标头添加CSRF令牌.
带有Angular的Laravel 5会自动为您完成此操作.
http://laravel.com/docs/5.1/routing#csrf-x-xsrf-token
我认为我的解决方案不那么痛苦,而且更灵活,特别是它认为在Karma上测试你的App.
首先将此代码添加到主视图中
<meta name="csrf-token" content="{{ csrf_token() }}">
Run Code Online (Sandbox Code Playgroud)
我们已将csrf令牌保存到html内容中而不添加路由.
现在我们通过CSRF令牌保护AngularJs App的所有请求
/**
*
* 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);
Run Code Online (Sandbox Code Playgroud)
我们需要为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;
}]);
Run Code Online (Sandbox Code Playgroud)
最后,我们需要在laravel一侧为这一变化需要新的过滤器.
Route::filter('csrfInHeader', function($route, $request) {
if (Session::token() !== (string) $request->header('X-CSRF-TOKEN') ) {
throw new Illuminate\Session\TokenMismatchException;
}
});
Run Code Online (Sandbox Code Playgroud)
"csrfInHeader"过滤器将通过angular app检查所有http请求.您不需要为每个请求添加csrf令牌.另外,如果你通过Karma测试你的应用程序,你将不会努力在测试中获得csrf令牌.
| 归档时间: |
|
| 查看次数: |
36220 次 |
| 最近记录: |