web-dev-qa-db-fra.com

Comment envoyer csrf_token () à l'intérieur du formulaire AngularJS en utilisant Laravel API?

J'essaie de créer une application angular + laravel rest. Je peux obtenir les vues de ma base de données. Lorsque j'essaie d'ajouter de nouveaux éléments. J'obtiens 500 error me disant que le jeton csrf ne correspond pas. Ma disposition de formulaire est:

<form class="form-horizontal" ng-submit="addItem()">

  <input type="text" ng-model="itemEntry" placeholder="Type and hit Enter to add item">
</form>

Voici comment j'essaie d'ajouter un élément à la base de données:

$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);
        });

}

Voici mon filtre que j'utilise pour mon application:

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

Dans mes vues de lame, j'utilise ceci et cela fonctionne:

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

Comment envoyer le csrf_token lorsque j'utilise des formulaires html?

Merci

Edit 1: L'ajout d'un en-tête à la demande de publication comme ceci ne donne pas d'erreurs.

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

Une option sera d'injecter le jeton CSRF en tant que constante. Ajoutez ce qui suit dans votre balise head:

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

Ensuite, dans vos méthodes de module, il peut être injecté en cas de besoin.

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

Peut-être serez-vous intéressé à jeter un œil au code source de ce exemple Laravel + projet AngularJS .

29
Rubens Mariuzzo

la solution acceptée par Rubens Mariuzzo fonctionne, mais je pense que j'ai trouvé une solution alternative que je trouve meilleure.

De cette façon, vous n'avez pas à transmettre les données du script html à votre application angularjs et il y a une meilleure séparation des préoccupations. Par exemple. Cela vous permet d'avoir votre Laravel APP comme juste une API.

Ma solution consiste à obtenir le jeton CSRF via une demande d'API et à définir cette valeur comme constante.

En outre, au lieu d'injecter le jeton CSRF en cas de besoin, vous définissez le jeton dans un en-tête par défaut qui serait vérifié par le serveur sur toute demande http API.

L'exemple montre laravel, cependant tout framework sérieux devrait être en mesure d'offrir quelque chose de similaire.

Itinéraire CSRF à LARAVEL:

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

Protection des itinéraires avec le before => 'api.csrf' Filtre

// 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');
});

Le api.csrf filtre

// 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);
}
});

Le truc AngularJS a mis cela dans app.js:

Version de blocage:

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;
}]);

Version non bloquante

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);

Désormais, la constante CSRF_TOKEN est injectée en tant qu'en-tête dans TOUTES les requêtes http de l'application AngularJS et TOUTES les routes API sont protégées.

23
Gravy

Si vous utilisez Laravel 5, pas besoin pour ajouter un jeton CSRF à Angular en-têtes http.

Laravel 5 avec Angular faites cela automatiquement pour vous.

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

22
Modder

Je pense que ma solution est moins douloureuse et beaucoup plus flexible, en particulier elle pense tester votre application sur Karma.

Ajoutez d'abord ce code à votre vue principale

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

Nous avons enregistré le jeton csrf dans du contenu html sans ajouter de route.

Maintenant, nous protégeons toutes les demandes d'AngularJs App par jeton 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); 

Nous devons configurer les en-têtes http par défaut pour Angular. Ajoutons notre jeton csrf aux en-têtes d'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;

 }]);

Enfin, nous devons avoir besoin d'un nouveau filtre pour ces changements du côté de laravel.

Route::filter('csrfInHeader', function($route, $request) {

    if (Session::token() !== (string) $request->header('X-CSRF-TOKEN') ) {

        throw new Illuminate\Session\TokenMismatchException;

    }
});

Le filtre "csrfInHeader" vérifiera toutes les requêtes http par angular. Vous n'avez pas besoin d'ajouter de jeton csrf à chaque demande. De plus, si vous testez votre application par Karma, vous n'aurez aucun effort pour obtenir csrf jeton sur les tests ..

7
MURATSPLAT

La façon la plus simple de le faire

Route::get('/getToken','Controller@getToken');

Dans votre fichier web ou api.php

Dans le contrôleur

public function getToken(){

          return csrf_token();

    }

Placez ce code

Dans Angular app

$http.get("http://localhost:8000/getToken")
  .then(function(response) {
    alert(response.data)
  });

Un moyen sûr d'obtenir csrf_token ()

1
Usama Shahid