62 votes

AngularJS: Comment envoyer un jeton d'authentification avec des requêtes de ressources $?

Je veux envoyer un jeton d'authentification lors de la demande d'une ressource à partir de mon API.

J'ai fait de mettre en œuvre un service à l'aide de $de ressources:

factory('Todo', ['$resource', function($resource) {
 return $resource('http://localhost:port/todos.json', {port:":3001"} , {
   query: {method: 'GET', isArray: true}
 });
}])

Et j'ai un service qui stocke le jeton d'authentification:

factory('TokenHandler', function() {
  var tokenHandler = {};
  var token = "none";

  tokenHandler.set = function( newToken ) {
    token = newToken;
  };
  tokenHandler.get = function() {
    return token;
  };

  return tokenHandler;
});

Je voudrais envoyer le jeton de tokenHandler.get avec chaque demande de les envoyer via l' Todo de service. J'ai été en mesure de l'envoyer en le plaçant dans l'appel d'une action spécifique. Par exemple cela fonctionne:

Todo.query( {access_token : tokenHandler.get()} );

Mais je préfère définir l'access_token comme paramètre dans l' Todo de service, il doit être envoyé à chaque appel. Et pour améliorer la SEC. Mais tout dans l'usine est exécutée qu'une seule fois, de sorte que le access_token devrait être disponible avant la définition de l'usine et qu'il ne peut pas changer par la suite.

Est-il possible de mettre une mise à jour dynamiquement les paramètres de la requête dans le service?

60voto

nblumoe Points 2035

Merci à Andy Joslin. J'ai repris son idée d'emballage de la ressource actions. Le service de la ressource ressemble à ceci maintenant:

.factory('Todo', ['$resource', 'TokenHandler', function($resource, tokenHandler) {
  var resource = $resource('http://localhost:port/todos/:id', {
    port:":3001",
    id:'@id'
    }, {
      update: {method: 'PUT'}
    });

  resource = tokenHandler.wrapActions( resource, ["query", "update"] );

  return resource;
}])

Comme vous pouvez le voir la ressource est définie de la manière habituelle, en premier lieu. Dans mon exemple, cela inclut une action personnalisée appelait update. Ensuite, la ressource est remplacé par le retour de l' tokenHandler.wrapAction() méthode qui prend de la ressource et un tableau des actions en tant que paramètres.

Comme vous pouvez vous attendre la dernière méthode fait encapsule les actions à inclure dans auth jeton dans chaque requête et retourne une ressource modifié. Allons donc jeter un oeil sur le code pour que:

.factory('TokenHandler', function() {
  var tokenHandler = {};
  var token = "none";

  tokenHandler.set = function( newToken ) {
    token = newToken;
  };

  tokenHandler.get = function() {
    return token;
  };

  // wrap given actions of a resource to send auth token with every
  // request
  tokenHandler.wrapActions = function( resource, actions ) {
    // copy original resource
    var wrappedResource = resource;
    for (var i=0; i < actions.length; i++) {
      tokenWrapper( wrappedResource, actions[i] );
    };
    // return modified copy of resource
    return wrappedResource;
  };

  // wraps resource action to send request with auth token
  var tokenWrapper = function( resource, action ) {
    // copy original action
    resource['_' + action]  = resource[action];
    // create new action wrapping the original and sending token
    resource[action] = function( data, success, error){
      return resource['_' + action](
        angular.extend({}, data || {}, {access_token: tokenHandler.get()}),
        success,
        error
      );
    };
  };

  return tokenHandler;
});

Comme vous pouvez le voir l' wrapActions() méthode crée une copie de la ressource à partir de ses paramètres et de boucles à travers l' actions tableau pour appeler une autre fonction tokenWrapper() pour chaque action. En fin de compte, il retourne la copie modifiée de la ressource.

L' tokenWrapperméthode tout d'abord crée une copie de préexistante des ressources d'action. Cette copie a une fin trait de soulignement. Donc, query()devient _query(). Ensuite, une nouvelle méthode remplace l'original query() méthode. Cette nouvelle méthode se terminera _query(), comme suggéré par Andy Joslin, afin de fournir le jeton d'authentification à chaque demande d'envoyer par le biais de cette action.

La bonne chose avec cette approche est que l'on peut toujours utiliser les actions prédéfinies qui viennent avec chaque angularjs ressources (get, requête, enregistrer, etc.), sans avoir à les redéfinir. Et dans le reste du code (à moins de contrôleurs par exemple), nous pouvons utiliser la valeur par défaut nom de l'action.

35voto

Ben W Points 2272

Une autre méthode consiste à utiliser un intercepteur HTTP qui remplace un en-tête d'autorisation "magique" par le jeton OAuth actuel. Le code ci-dessous est spécifique à OAuth, mais y remédier est un exercice simple pour le lecteur.

 // Injects an HTTP interceptor that replaces a "Bearer" authorization header
// with the current Bearer token.
module.factory('oauthHttpInterceptor', function (OAuth) {
  return {
    request: function (config) {
      // This is just example logic, you could check the URL (for example)
      if (config.headers.Authorization === 'Bearer') {
        config.headers.Authorization = 'Bearer ' + btoa(OAuth.accessToken);
      }
      return config;
    }
  };
});

module.config(function ($httpProvider) {
  $httpProvider.interceptors.push('oauthHttpInterceptor');
});
 

21voto

ricricucit Points 478

J'aime beaucoup cette approche:

http://blog.brunoscopelliti.com/authentication-to-a-restful-web-service-in-an-angularjs-web-app

où le jeton est toujours envoyé automatiquement dans l'en-tête de la demande sans avoir besoin d'un wrapper.

 // Define a new http header
$http.defaults.headers.common['auth-token'] = 'C3PO R2D2';
 

9voto

Andy Joslin Points 23231

Vous pouvez créer une fonction wrapper pour cela.

 app.factory('Todo', function($resource, TokenHandler) {
    var res= $resource('http://localhost:port/todos.json', {
        port: ':3001',
    }, {
        _query: {method: 'GET', isArray: true}
    });

    res.query = function(data, success, error) {
        //We put a {} on the first parameter of extend so it won't edit data
        return res._query(
            angular.extend({}, data || {}, {access_token: TokenHandler.get()}),
            success,
            error
        );
    };

    return res;
})
 

5voto

vpoulain Points 149

J'ai dû faire face à ce problème aussi. Je ne pense pas que ce soit une solution élégante, mais cela fonctionne et il y a 2 lignes de code:

Je suppose que vous obtenez votre jeton de votre serveur après une authentification dans SessionService par exemple. Ensuite, appelez ce genre de méthode:

    angular.module('xxx.sessionService', ['ngResource']).
    factory('SessionService', function( $http,  $rootScope) {

         //...
       function setHttpProviderCommonHeaderToken(token){
          $http.defaults.headers.common['X-AUTH-TOKEN'] = token;
       }  
   });
 

Après cela, toutes vos demandes de $ resource et $ http auront un jeton dans leur en-tête.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X