Mise en œuvre de l’API Node.js (SPA + API)

Ce document fait partie du scénario d’architecture SPA + API et explique comment mettre en œuvre l’API dans Node.js. Veuillez vous référer au scénario pour obtenir des informations sur la solution implémentation.

Le code source complet de la mise en œuvre de l’API Node.js se trouve dans ce dépôt GitHub.

1. Définir les points de terminaison de l’API

Nous utiliserons le cadre d’applications Web Express pour construire une API Node.js.

Créer un fichier package.json

Créez un dossier pour votre API-y et exécutez npm init. Cette action configurera votre fichier package.json.

Laissez les paramètres par défaut ou modifiez-les selon votre convenance.

Le package.json  de notre exemple ressemble à ce qui suit :

{
  "name": "timesheets-api",
  "version": "1.0.0",
  "description": "API used to add timesheet entries for employees and contractors",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/auth0-samples/auth0-pnp-timesheets.git"
  },
  "author": "Auth0",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/auth0-samples/auth0-pnp-timesheets/issues"
  },
  "homepage": "https://github.com/auth0-samples/auth0-pnp-timesheets#readme"
}

Was this helpful?

/

Installer les dépendances

Ensuite, nous devons définir nos dépendances. Nous utiliserons les modules suivants :

  • express : ce module ajoute le cadre d’applications Web Express.

  • cors : Le présent module ajoute la prise en charge de l’activation du CORS, ce qui est nécessaire car l’API sera appelée à partir d’une application à page unique qui s’exécute sur un domaine différent dans un navigateur Web.

  • jwks-rsa : cette bibliothèque récupère les clés de connexion RSA à partir d’un point de terminaison JWKS (JSON Web Key Set). À l’aide de expressJwtSecret nous pouvons générer un fournisseur de secret qui fournit la bonne clé de connexion à express-jwt en fonction du kid dans l’en-tête JWT. Pour en apprendre davantage, consultez node-jwks-rsa GitHub repository.

  • express-jwt : Ce module vous laisse authentifier les requêtes HTTP à l’aide de jetons JWT dans vos applications Node.js. Express-jwtusieurs fonctions qui facilitent le travail avec les JWT. Pour plus d’information consultez express-jwt GitHub repository.

  • body-parser : il s’agit d’un logiciel médiateur d’analyse de corps Node.js. Il extrait la partie entière du corps d’une requête entrante et l’expose sur req.body comme quelque chose de plus facile à interfacer. Pour plus d’informations et plusieurs alternatives, consultez le dépôt GitHub body-parser.

Pour installer ces dépendances, suivez les étapes suivantes :

npm install express cors express-jwt jwks-rsa body-parser express-jwt-authz --save

Was this helpful?

/

Implémenter les points de terminaison

Ouvrez votre répertoire API et créez un fichier  server.js . Votre code doit :

  • Obtenir les dépendances.

  • Implémenter le ou les points de terminaison.

  • Lancer le serveur API.

Voici notre exemple d’implémentation :

const express = require('express');
const app = express();
const { expressjwt: jwt } = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const cors = require('cors');
const bodyParser = require('body-parser');

// Enable CORS
app.use(cors());

// Enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: true
}));

// Create timesheets API endpoint
app.post('/timesheets', function(req, res){
  res.status(201).send({message: "This is the POST /timesheets endpoint"});
})

// Launch the API Server at localhost:8080
app.listen(8080);

Was this helpful?

/

Lancez votre serveur API en utilisant  node server et envoyez une requête HTTP POST à localhost:8080/timesheets. Vous verrez une réponse JSON avec le message This is the POST /timesheets endpoint.

Nous avons désormais notre point de terminaison, mais tout le monde peut l’appeler. Rendez-vous au paragraphe suivant pour voir comment nous pouvons résoudre ce problème.

2. Sécuriser les points de terminaison de l’API

Dans l’optique de valider notre jeton, nous utiliserons la fonction jwt fournie par le logiciel médiateur express-jwt, et jwks-rsa pour récupérer notre secret. Les bibliothèques remplissent les rôles suivants :

  1. express-jwt décode le jeton et achemine la demande l’en-tête et les données utiles vers jwksRsa.expressJwtSecret.

  2. jwks-rsa télécharge toutes les clés de connexion à partir du point de terminaison JWKS et vérifie si l’une des clés de connexion correspond à la valeur kid dans l’en-tête du jeton JWT. Si aucune des clés de connexion ne correspond à la valeur kidreçue, une erreur sera générée. Si nous avons une correspondance, nous transmettrons la bonne clé de connexion à express-jwt.

  3. express-jwt poursuivra sa propre logique pour valider la signature du jeton, l’expiration, l'audience et l’issuer.

Les étapes que nous suivrons dans notre code sont :

  • Créer la fonctionnalité logiciel médiateur pour valider le jeton d’accès.

  • Activez l’utilisation du logiciel médiateur dans nos chemins.

Vous pouvez également écrire du code pour véritablement enregistrer la feuille de temps dans une base de données. Voici notre exemple d’implémentation (certains codes sont omis aux fins de concision) :

// set dependencies - code omitted

// Enable CORS - code omitted

// Create middleware for checking the JWT
const checkJwt = jwt({
  // Dynamically provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    jwksUri: `https://{yourDomain}/.well-known/jwks.json`
  }),

  // Validate the audience and the issuer
  audience: '{YOUR_API_IDENTIFIER}', //replace with your API's audience, available at Dashboard > APIs
  issuer: 'https://{yourDomain}/',
  algorithms: [ 'RS256' ]
});

// Enable the use of request body parsing middleware - code omitted

// create timesheets API endpoint - code omitted
app.post('/timesheets', checkJwt, function(req, res){
  var timesheet = req.body;

  // Save the timesheet to the database...

  //send the response
  res.status(201).send(timesheet);
});
// launch the API Server at localhost:8080 - code omitted

Was this helpful?

/

Si nous lançons notre serveur maintenant et effectuons un HTTP POST verslocalhost:8080/timesheets nous obtiendrons le message d’erreurMissing or invalid token, ce qui est correct, car nous n’avons pas envoyé de jeton d’accès dans notre demande).

Pour tester également le scénario de fonctionnement, nous devons :

  • Obtenir un jeton d’accès Pour plus d’informations sur la procédure à suivre pour y parvenir, reportez-vous à : Get an Access Token (Obtenir un jeton d’accès).

  • Invoquez l’API en ajoutant un en-tête Authorization (Autorisation) à notre requête avec la valeur Bearer ACCESS_TOKEN (Porteur de jeton d’accès), où ACCESS_TOKEN (jeton d’accès) est la valeur du jeton que nous avons récupéré à la première étape.

3. Vérifiez les permissions de l’application

Á cette étape nous ajouterons à notre mise en œuvre la possibilité de vérifier si l’application a des autorisations (ou des permissions) pour utiliser notre point de terminaison afin de créer une feuille de temps. En particulier, nous voulons nous rassurer que le jeton a la bonne permission, qui est batch:upload.

Pour y parvenir, nous utilisons le paquet express-jwt-authz Node.js, donc ajoutez-le à votre projet :

npm install express-jwt-authz --save

Was this helpful?

/

Maintenant, ajoutez un appel à jwtAuthz(...) à votre logiciel médiateur pour vous assurer que le jeton JWT contient une permission particulière afin d’exécuter un point de terminaison particulier.

Nous ajouterons une dépendance supplémentaire. La bibliothèque express-jwt-authz , utilisée conjointement avec express-jwt, valide le jeton JWT et s’assure qu’il possède les autorisations adéquates pour appeler le point de terminaison souhaité. Pour plus d’informations, consultez le référentiel express-jwt-authz GitHub.

Voici notre exemple d’implémentation (certains codes sont omis aux fins de concision) :

// set dependencies - some code omitted
const jwtAuthz = require('express-jwt-authz');

// Enable CORS - code omitted

// Create middleware for checking the JWT - code omitted

// Enable the use of request body parsing middleware - code omitted

// create timesheets API endpoint
app.post('/timesheets', checkJwt, jwtAuthz(['create:timesheets'], { customUserKey: 'auth' }), function(req, res){
  var timesheet = req.body;

  // Save the timesheet to the database...

  //send the response
  res.status(201).send(timesheet);
})

// launch the API Server at localhost:8080 - code omitted

Was this helpful?

/

Si nous invoquons notre API avec un jeton qui n’inclut pas cette permission, nous devrions obtenir le message d’erreur Interdit avec le code d’état HTTP 403. Vous pouvez l’essayer en supprimant cette permission de votre API.

4. Déterminer l’identité de l’utilisateur

Le logiciel médiateur express-jwt utilisé pour valider le jeton JWT configure également req.auth avec les informations contenues dans le jeton JWT. Si vous voulez utiliser la demande sub pour identifier l’utilisateur de manière unique, vous pouvez simplement utiliser req.auth.sub.

Dans le cas de l’application de feuilles de temps, nous souhaitons cependant utiliser l’adresse courriel de l’utilisateur comme identifiant unique.

La première chose que nous devons faire est d’écrire une règle qui ajoutera l’adresse courriel de l’utilisateur au jeton d’accès. Accédez à la section Règles du Dashboard, puis cliquez sur le boutonCréer une règle.

Vous pouvez donner à la règle un nom descriptif, par exemple Ajouter courriel au jeton d’accès, puis utiliser le code suivant pour la règle :

function (user, context, callback) {
  const namespace = 'https://api.exampleco.com/';
  context.accessToken[namespace + 'email'] = user.email;
  callback(null, user, context);
}

Was this helpful?

/

Le namespace est utilisé pour s’assurer que la requête possède un nom unique et n’entre pas en conflit avec les noms de requêtes OIDC standard. Cependant, Auth0 prend en charge les demandes personnalisées avec et sans espace de noms. Pour plus d’informations sur les demandes personnalisées, consultez Créer des demandes personnalisées.

Ensuite, dans votre API, vous pouvez récupérer la valeur de la demande à partir de req.auth, et l’utiliser en tant qu’identité unique de l’utilisateur que vous pouvez associer aux entrées de feuilles de temps.

app.get('/timesheets', checkJwt, jwtAuthz(['read:timesheets'], { customUserKey: 'auth' }), function(req, res) {
  var timesheet = req.body;

  // Associate the timesheet entry with the current user
  var userId = req.auth['https://api.exampleco.com/email'];
  timesheet.user_id = userId;

  // Save the timesheet to the database...

  //send the response
  res.status(201).send(timesheet);
});

Was this helpful?

/