如何使用 Laravel API 在 AngularJS 表单中发送 csrf_token()?
Posted
技术标签:
【中文标题】如何使用 Laravel API 在 AngularJS 表单中发送 csrf_token()?【英文标题】:How to send csrf_token() inside AngularJS form using Laravel API? 【发布时间】:2013-08-22 14:26:13 【问题描述】:我正在尝试构建一个 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: 像这样向 post 请求添加标头不会产生错误。
$http(
method : 'POST',
url : '/shop',
data : $scope.itemEntry, // pass in data as strings
headers : 'Content-Type': 'application/x-www-form-urlencoded'
);
【问题讨论】:
【参考方案1】:一个选项是将 CSRF 令牌作为常量注入。在你的 head 标签中添加以下内容:
<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的源代码。
【讨论】:
您好,我在头部添加了脚本。我注入了 CSRF_TOKEN 。如何在表单中添加它?顺便说一句,我编辑了我的代码。 我仍然无法管理它,我阅读了端到端的代码。我编辑了 $scope.addItem 。可以看看吗?【参考方案2】:Rubens Mariuzzo 接受的解决方案有效,但我认为我找到了一个我认为更好的替代解决方案。
这样您就不必将 html 脚本中的数据传递到您的 angularjs 应用程序中,并且可以更好地分离关注点。例如。这允许您将 Laravel 应用程序作为一个 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 路由都受到保护。
【讨论】:
嘿,我为该解决方案添加了另一种选择。如果它也是一个不错的解决方案,您能否检查并发表您的评论? @ytsejam - 我不明白如何在标头中指定内容类型是从服务器获取 CSRF 令牌到 AngularJS 应用程序的替代解决方案。 我跟着这个教程scotch.io/tutorials/php/… @Gravy 您是否从同一个域为您的 Angular 应用程序提供服务?我目前在 api.example.com 有我的 api,并且从 example.com 提供了 angular,所以我在进行会话时遇到问题,因为它被认为是跨源的。 这不适用于 REST api,令牌不会相同。【参考方案3】:如果你使用 Laravel 5,不需要将 CSRF 令牌添加到 Angular http headers。
带有 Angular 的 Laravel 5 会自动为您完成这项工作。
http://laravel.com/docs/5.1/routing#csrf-x-xsrf-token
【讨论】:
太棒了。完全错过了这个【参考方案4】:我认为我的解决方案更轻松,更灵活,尤其是它认为在 Karma 上测试您的应用程序。
首先将此代码添加到您的主视图
<meta name="csrf-token" content=" csrf_token() ">
我们已将 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://***.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;
]);
最后,我们必须在 laravel 侧需要新的过滤器来进行此更改..
Route::filter('csrfInHeader', function($route, $request)
if (Session::token() !== (string) $request->header('X-CSRF-TOKEN') )
throw new Illuminate\Session\TokenMismatchException;
);
"csrfInHeader" 过滤器将通过 Angular 应用检查所有 http 请求。您不需要为每个请求添加 csrf 令牌。另外,如果您通过 Karma 测试您的应用程序,您将不会努力在测试中获取 csrf 令牌..
【讨论】:
【参考方案5】:最简单的方法
Route::get('/getToken','Controller@getToken');
在您的 web 或 api.php 文件中
在控制器中
public function getToken()
return csrf_token();
放置此代码
在 Angular 应用中
$http.get("http://localhost:8000/getToken")
.then(function(response)
alert(response.data)
);
获取 csrf_token() 的安全方法
【讨论】:
以上是关于如何使用 Laravel API 在 AngularJS 表单中发送 csrf_token()?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Laravel 4 中使用 RESTful API? [关闭]
如何将 Laravel 项目转换为 laravel api?