Site icon Blog ARC Optimizer

Construire une API REST simple avec Node et OAuth 2.0 –


Cet article a été publié à l'origine sur le blog des développeurs Okta . Merci de soutenir les partenaires qui ont rendu SitePoint possible.

JavaScript est utilisé partout sur le Web – presque toutes les pages Web contiennent au moins du code JavaScript, et même si ce n’est pas le cas, votre navigateur a probablement une sorte d’extension injecte de toute façon des bits de code JavaScript sur la page. Il est difficile à éviter en 2018.

JavaScript peut également être utilisé en dehors du contexte d'un navigateur, de l'hébergement d'un serveur Web au contrôle d'une voiture RC ou de l'exécution d'un système d'exploitation complet. Parfois, vous voulez que deux serveurs se parlent, que ce soit sur un réseau local ou sur Internet.

Aujourd'hui, je vais vous montrer comment créer une API REST en utilisant Node.js et la sécuriser avec OAuth 2.0. pour éviter les demandes injustifiées. Les API REST sont partout sur le Web, mais sans les outils appropriés, il faut une tonne de code standard. Je vais vous montrer comment utiliser quelques outils incroyables qui facilitent tout, y compris Okta pour implémenter le flux d'informations d'identification du client, qui connecte deux machines en toute sécurité sans le contexte d'un utilisateur.

Construisez votre serveur de noeuds [19659006] La configuration d'un serveur Web dans Node est assez simple avec la bibliothèque JavaScript Express . Créez un nouveau dossier qui contiendra votre serveur.
 $ mkdir rest-api

Le noeud utilise un package.json pour gérer les dépendances et définir votre projet. Pour en créer un, utilisez npm init qui vous posera quelques questions pour vous aider à initialiser le projet. Pour le moment, vous pouvez utiliser le standard JS pour appliquer une norme de codage et l'utiliser comme test.

 $ cd rest-api

$ npm init
Cet utilitaire vous guidera à travers la création d'un fichier package.json.
Il ne couvre que les éléments les plus courants et essaie de deviner les valeurs par défaut.

Voir `npm help json` pour une documentation définitive sur ces champs
et exactement ce qu'ils font.

Utilisez `npm install ` pour installer un paquet et
enregistrez-le en tant que dépendance dans le fichier package.json.

Appuyez sur ^ C à tout moment pour quitter.
nom du paquet: (rest-api)
version: (1.0.0)
description: Un catalogue de pièces
point d'entrée: (index.js)
commande de test: standard
dépôt git:
mots clés:
auteur:
licence: (ISC)
A propos d'écrire à /Users/Braden/code/rest-api/package.json:

{
  "name": "rest-api",
  "version": "1.0.0",
  "description": "Un catalogue de pièces",
  "main": "index.js",
  "scripts": {
    "test": "standard"
  },
  "auteur": "",
  "licence": "ISC"
}


Est-ce correct? (Oui)

Le point d'entrée par défaut est index.js . Vous devez donc créer un nouveau fichier avec ce nom. Le code suivant vous fournira un serveur vraiment basique qui ne fait rien d'autre que d'écouter sur le port 3000 par défaut.

index.js

 const express = require ('express')
const bodyParser = require ('analyseur de corps')
const {promisify} = require ('util')

const app = express ()
app.use (bodyParser.json ())

const startServer = async () => {
  const port = process.env.SERVER_PORT || 3000
  attend promisify (app.listen) .bind (app) (port)
  console.log (`Ecouter sur le port $ {port}`)
}

startServer ()

La fonction promisify de util vous permet de prendre une fonction qui attend un rappel et renverra une promesse, qui est la nouvelle norme en ce qui concerne le traitement du code asynchrone. Cela nous permet également d'utiliser la syntaxe relativement récente / et de rendre notre code plus joli.

Pour que cela fonctionne, vous devez installer les dépendances exige en haut du fichier. Ajoutez-les en utilisant npm install . Cela enregistrera automatiquement certaines métadonnées dans votre fichier package.json et les installera localement dans un dossier node_modules .

Remarque: : vous ne devriez jamais commettre node_modules au contrôle de code source car il a tendance à être rapidement gonflé, et le fichier package-lock.json gardera une trace des versions exactes que vous avez utilisées si vous les installez sur un autre ordinateur. le même code.

 $ npm install express@4.16.3 util@0.11.0

Pour un linting rapide, installez la norme en tant que dépendance de développement, puis exécutez-la pour vous assurer que votre code est au pair.

 $ npm install --save-dev standard@11.0.1
Test npm $

> rest-api@1.0.0 test / Users / bmk / code / okta / apps / rest-api
> standard

Si tout va bien, vous ne devriez voir aucune sortie après la ligne > standard . S'il y a une erreur, cela peut ressembler à ceci:

 $ npm test

> rest-api@1.0.0 test / Users / bmk / code / okta / apps / rest-api
> standard

standard: Utiliser le style standard JavaScript (https://standardjs.com)
standard: Exécutez `standard --fix` pour corriger automatiquement certains problèmes.
  /Users/Braden/code/rest-api/index.js:3:7: Espacement cohérent attendu
  /Users/Braden/code/rest-api/index.js:3:18: Virgule de fin inattendue.
  /Users/Braden/code/rest-api/index.js:3:18: Un espace est requis après ','.
  /Users/Braden/code/rest-api/index.js:3:38: Point-virgule supplémentaire.
npm ERR! Test échoué. Voir ci-dessus pour plus de détails.

Maintenant que votre code est prêt et que vous avez installé vos dépendances, vous pouvez exécuter le serveur avec le noeud . (le . dit de regarder le répertoire actuel, puis vérifie votre fichier package.json pour voir que le fichier principal à utiliser dans ce répertoire est index.js ):

 $ node.

Écoute sur le port 3000

Pour tester son fonctionnement, vous pouvez utiliser la commande curl . Il n'y a pas encore de point final, donc express retournera une erreur:

 $ curl localhost: 3000 -i
HTTP / 1.1 404 introuvable
X-Powered-By: Express
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
Type de contenu: text / html; charset = utf-8
Longueur du contenu: 139
Date: jeu. 16 août 2018 01:34:53 GMT
Connexion: rester en vie





 Erreur 


 Impossible de GET / 



Même si cela dit que c’est une erreur, c’est bien. Vous n'avez pas encore configuré de terminal, par conséquent, la seule chose à faire pour Express est une erreur 404. Si votre serveur ne fonctionnait pas du tout, vous recevriez une erreur comme celle-ci:

 $ curl localhost: 3000 -i
curl: (7) Impossible de se connecter au port localhost 3000: connexion refusée

Construisez votre API REST avec Express, Sequelize et Epilogue

Maintenant que vous avez un serveur Express opérationnel, vous pouvez ajouter une API REST. C'est en fait beaucoup plus simple que vous ne le pensez. Le moyen le plus simple que j'ai vu consiste à utiliser Sequelize pour définir votre schéma de base de données et Epilogue à créer certains points de terminaison API REST avec un passe-partout presque nul.

pour ajouter ces dépendances à votre projet. Sequelize doit également savoir comment communiquer avec la base de données. Pour l'instant, utilisez SQLite car il nous permettra de démarrer rapidement.

 npm install sequelize@4.38.0 epilogue@0.7.1 sqlite3@4.0.2

Créez un nouveau fichier database.js avec le code suivant. Je vais expliquer chaque partie plus en détail ci-dessous.

database.js

 const Sequelize = require ('sequelize')
const epilogue = require ('épilogue')

const database = new Sequelize ({
  dialecte: 'sqlite',
  stockage: './test.sqlite',
  operatorsAliases: false
})

const Part = database.define ('parts', {
  Numéro de pièce: Sequelize.STRING,
  modelNumber: Sequelize.STRING,
  nom: Sequelize.STRING,
  description: Sequelize.TEXT
})

const initializeDatabase = async (app) => {
  epilogue.initialize ({app, sequelize: database})

  epilogue.resource ({
    modèle: Part,
    points finaux: ['/parts', '/parts/:id']
  })

  attendre database.sync ()
}

module.exports = initializeDatabase

Il ne vous reste plus qu'à importer ce fichier dans votre application principale et à lancer la fonction d'initialisation. Apportez les ajouts suivants à votre fichier index.js .

index.js

 @@ -2,10 +2,14 @@ const express = require ('express')
 const bodyParser = require ('analyseur de corps')
 const {promisify} = require ('util')

+ const initializeDatabase = require ('./ database')
+
 const app = express ()
 app.use (bodyParser.json ())

 const startServer = async () => {
+ attend initializeDatabase (app)
+
   const port = process.env.SERVER_PORT || 3000
   attend promisify (app.listen) .bind (app) (port)
   console.log (`Ecouter sur le port $ {port}`)

Vous pouvez maintenant tester les erreurs de syntaxe et exécuter l'application si tout semble bon:

 $ npm test && node.

> rest-api@1.0.0 test / Users / bmk / code / okta / apps / rest-api
> standard

Exécution (par défaut): CREATE TABLE SI NOT EXISTS `parties` (` id` INTEGER PRIMARY KEY AUTOINCREMENT, `partNumber` VARCHAR (255),` modelNu
mber` VARCHAR (255), `name` VARCHAR (255),` description` TEXT, `createdAt` DATETIME NOT NULL,` updatedAt` DATETIME NOT NULL);
Exécution (par défaut): PRAGMA INDEX_LIST (`parts`)
Écoute sur le port 3000

Dans un autre terminal, vous pouvez tester que cela fonctionne (pour formater la réponse JSON, j'utilise une interface CLI json installée globalement à l'aide de npm install --global json ):

 $ curl localhost: 3000 / parts
[]

$ curl localhost: 3000 / parts -X POST -d '{
  "partNumber": "abc-123",
  "modelNumber": "xyz-789",
  "nom": "Soupe à l'alphabet",
  "description": "Soupe avec lettres et chiffres"
} '-H' content-type: application / json '-s0 | json
{
  "id": 1,
  "partNumber": "abc-123",
  "modelNumber": "xyz-789",
  "nom": "Soupe à l'alphabet",
  "description": "Soupe contenant des lettres et des chiffres",
  "updatedAt": "2018-08-16T02: 22: 09.446Z",
  "createdAt": "2018-08-16T02: 22: 09.446Z"
}

$ curl localhost: 3000 / parts -s0 | json
[
  {
    "id": 1,
    "partNumber": "abc-123",
    "modelNumber": "xyz-789",
    "name": "Alphabet Soup",
    "description": "Soup with letters and numbers in it",
    "createdAt": "2018-08-16T02:22:09.446Z",
    "updatedAt": "2018-08-16T02:22:09.446Z"
  }
]

N'hésitez pas à sauter cette section si vous avez suivi tout cela, mais j'ai promis une explication.

La fonction Sequelize crée une base de données. C'est là que vous configurez des détails, tels que le dialecte SQL à utiliser. Pour le moment, utilisez SQLite pour démarrer rapidement.

 const database = new Sequelize ({
  dialecte: 'sqlite',
  stockage: './test.sqlite',
  operatorsAliases: false
})

Une fois la base de données créée, vous pouvez en définir le schéma à l'aide de database.define pour chaque table. Créez un tableau appelé parts avec quelques champs utiles pour suivre les pièces. Par défaut, Sequelize crée et met à jour automatiquement les champs id createdAt et updatedAt lorsque vous créez ou mettez à jour une ligne.

 const Part = database. define ('parts', {
  Numéro de pièce: Sequelize.STRING,
  modelNumber: Sequelize.STRING,
  nom: Sequelize.STRING,
  description: Sequelize.TEXT
})

Epilogue nécessite un accès à votre application Express afin d'ajouter des points de terminaison. Cependant, l'application est définie dans un autre fichier. Une façon de gérer cela est d'exporter une fonction qui prend l'application et fait quelque chose avec. Dans l'autre fichier, lorsque vous importez ce script, vous l'exécutez comme initializeDatabase (app) .

Epilogue doit être initialisé avec l'application et la base de données . Vous définissez ensuite les points de terminaison REST que vous souhaitez utiliser. La fonction de la ressource comprendra les points de terminaison pour les verbes GET POST PUT et DELETE principalement de manière automagique. .

Pour créer la base de données, vous devez exécuter database.sync () qui renvoie une promesse. Vous voudrez attendre qu'il soit terminé avant de démarrer votre serveur.

La commande module.exports indique que la fonction initializeDatabase peut être importée à partir d'un autre fichier.

 const initializeDatabase = async (app) => {
  epilogue.initialize ({app, sequelize: database})

  epilogue.resource ({
    modèle: Part,
    points finaux: ['/parts', '/parts/:id']
  })

  attendre database.sync ()
}

module.exports = initializeDatabase

Sécurisez votre API REST Node + Express avec OAuth 2.0

Maintenant que vous avez une API REST opérationnelle, imaginez que vous souhaitiez qu’une application spécifique l’utilise depuis un emplacement distant. Si vous hébergez cela sur Internet en l'état, tout le monde peut ajouter, modifier ou supprimer des parties à sa guise.

Pour éviter cela, vous pouvez utiliser le flux d'informations d'identification du client OAuth 2.0. C'est un moyen de permettre à deux serveurs de communiquer entre eux, sans le contexte d'un utilisateur. Les deux serveurs doivent convenir à l'avance pour utiliser un serveur d'autorisation tiers. Supposons qu'il existe deux serveurs, A et B, et un serveur d'autorisation. Le serveur A héberge l'API REST et le serveur B souhaite accéder à l'API.

  • Le serveur B envoie une clé secrète au serveur d'autorisation pour prouver son identité et demander un jeton temporaire.
  • Le serveur B consomme alors
  • Le serveur A demande au serveur d'autorisation certaines métadonnées pouvant être utilisées pour vérifier les jetons.
  • Le serveur A vérifie la demande du serveur B.
    • S'il est valide, une réponse réussie est envoyée et le serveur B est satisfait.
    • Si le jeton n'est pas valide, un message d'erreur est envoyé à la place et aucune information sensible n'est divulguée.

] C'est là qu'intervient Okta. Okta peut agir comme un serveur d'autorisation pour vous permettre de sécuriser vos données. Vous vous demandez probablement “Pourquoi Okta? Eh bien, c’est plutôt cool de construire une application REST, mais c’est encore plus cool de construire une sécurisée . Pour ce faire, vous souhaitez ajouter une authentification afin que les utilisateurs doivent se connecter avant de visualiser / modifier des groupes. Chez Okta, notre objectif est de rendre la gestion des identités beaucoup plus facile, plus sécurisée et plus évolutive que ce à quoi vous êtes habitué. Okta est un service cloud qui permet aux développeurs de créer, modifier et stocker en toute sécurité des comptes utilisateur et des données de compte utilisateur, et de les connecter à une ou plusieurs applications. Notre API vous permet de:

Si vous n'en avez pas déjà un, inscrivez-vous pour un compte développeur et commençons!

Après avoir créé votre compte, connectez-vous à votre console de développeur, accédez à API puis à l'onglet Authorization Servers . Cliquez sur le lien vers votre serveur par défaut .

À partir de cet onglet Paramètres copiez le champ Émetteur . Vous devez enregistrer ceci quelque part que votre application Node peut lire. Dans votre projet, créez un fichier nommé .env qui ressemble à ceci:

.env

 ISSUER = https: // {yourOktaDomain} / oauth2 / default

La valeur de ISSUER doit correspondre à la valeur du champ Issuer URI de la page Paramètres.

] Note : En règle générale, vous ne devez pas stocker ce fichier .env dans le contrôle de code source. Cela permet à plusieurs projets d'utiliser le même code source sans avoir besoin d'un fork distinct. Il veille également à ce que vos informations sécurisées ne soient pas publiques (en particulier si vous publiez votre code en tant que source ouverte).

Ensuite, accédez à l'onglet Scopes . Cliquez sur le bouton Ajouter une étendue et créez une étendue pour votre API REST. Vous devrez lui donner un nom (par exemple parts_manager ) et vous pourrez lui donner une description si vous le souhaitez.

Vous devez ajouter le nom de la portée de votre fichier .env afin que votre code puisse y accéder.

.env

 ISSUER = https: // {yourOktaDomain} / oauth2 / default
SCOPE = parts_manager

Maintenant, vous devez créer un client. Naviguez vers Applications puis cliquez sur Ajouter une application . Sélectionnez Service puis cliquez sur Suivant . Entrez un nom pour votre service (par exemple, Parts Manager ), puis cliquez sur Terminé .

Ceci vous mènera à une page contenant vos informations d'identification client. Ce sont les informations d'identification dont le serveur B (celui qui consommera l'API REST) ​​aura besoin pour s'authentifier. Pour cet exemple, le code client et serveur sera dans le même référentiel, alors allez-y et ajoutez ces données à votre fichier .env . Veillez à remplacer {yourClientId} et {yourClientSecret} par les valeurs de cette page.

 CLIENT_ID = {yourClientId}
CLIENT_SECRET = {yourClientSecret}

Créer un middleware pour vérifier les jetons dans Express

Dans Express, vous pouvez ajouter un middleware qui s'exécutera avant chaque noeud final. Vous pouvez ensuite ajouter des métadonnées, définir des en-têtes, enregistrer certaines informations ou même annuler la demande plus tôt et envoyer un message d'erreur. Dans ce cas, vous souhaiterez créer un middleware qui vérifie le jeton envoyé par le client. Si le jeton est valide, il continue vers l'API REST et renvoie la réponse appropriée. Si le jeton est invalide, il répondra avec un message d'erreur afin que seules les machines autorisées y aient accès.

Pour valider les jetons, vous pouvez utiliser le middleware Okta. Vous aurez également besoin d’un outil appelé dotenv pour charger les variables d’environnement:

 npm install dotenv@6.0.0 @ okta / jwt-verifier @ 0.0.12

Créez maintenant un fichier nommé auth.js qui exportera le middleware:

auth.js

 const OktaJwtVerifier = require ('@ okta / jwt-verifier')

const oktaJwtVerifier = new OktaJwtVerifier ({issuer: process.env.ISSUER})

module.exports = async (req, res, next) => {
  essayez {
    const {autorisation} = req.headers
    if (! autorisation) jette une nouvelle erreur ('Vous devez envoyer un en-tête d'autorisation')

    const [authType, token] = authorization.trim (). split ('')
    if (authType! == 'Bearer') lance une nouvelle erreur ('Attendu un jeton porteur')

    const {claims} = wait oktaJwtVerifier.verifyAccessToken (jeton)
    if (! claims.scp.includes (process.env.SCOPE)) {
      jeter une nouvelle erreur ('Impossible de vérifier la portée appropriée')
    }
    prochain()
  } attraper (erreur) {
    suivant (error.message)
  }
}

Cette fonction vérifie d’abord que l’en-tête et l’autorisation figure sur la demande et génère une erreur sinon. S'il existe, il devrait ressembler à Bearer {token} {jeton} est une chaîne JWT . Cela provoquera une autre erreur si l’en-tête ne commence pas par Bearer . Nous envoyons ensuite le jeton à JWT Verifier d’Okta pour valider le jeton. Si le jeton n'est pas valide, le vérificateur JWT génère une erreur. Sinon, il retournera un objet avec des informations. Vous pouvez alors vérifier que les revendications incluent la portée que vous attendez.

Si tout se passe bien, il appelle la fonction next () sans aucun paramètre, ce qui indique à Express qu'il est possible de continuer à la fonction suivante de la chaîne (soit un autre middleware ou le point final final). Si vous passez une chaîne de caractères dans la fonction next Express la traite comme une erreur qui sera transmise au client et ne se poursuivra pas dans la chaîne.

Vous devez toujours importer cette fonction et ajoutez-le en tant que middleware à votre application. Vous devez également charger dotenv en haut de votre fichier d'index pour vous assurer que les variables d'environnement de .env sont chargées dans votre application. Apportez les modifications suivantes à index.js :

index.js

 @@ -1,11 +1,14 @@
+ require ('dotenv'). config ()
 const express = require ('express')
 const bodyParser = require ('analyseur de corps')
 const {promisify} = require ('util')

+ const authMiddleware = require ('./ auth')
 const initializeDatabase = require ('./ database')

 const app = express ()
 app.use (bodyParser.json ())
+ app.use (authMiddleware)

 const startServer = async () => {
   attendre initializeDatabase (app)

Pour tester que les requêtes sont correctement bloquées, essayez de l'exécuter à nouveau…

 $ npm test && node.

… puis, dans un autre terminal, exécuter quelques commandes curl à tester:

Un en-tête d'autorisation est requis:

 $ curl localhost: 3000 / parts




 Erreur 


 Vous devez envoyer un en-tête d'autorisation 



Un jeton de support est requis dans l'en-tête d'autorisation:

 $ curl localhost: 3000 / parts -H 'Autorisation: Basic asdf: 1234'




 Erreur 


 Attendu un jeton porteur 



Le jeton Bearer est valide:

 $ curl localhost: 3000 / parts -H 'Authorization: Bearer asdf'




 Erreur 


 Impossible d'analyser Jwt 



Créer un client de test dans le nœud

Vous avez maintenant désactivé l'accès à l'application pour quelqu'un sans jeton valide, mais comment obtenir un jeton et l'utiliser? Je vais vous montrer comment écrire un client simple dans Node, ce qui vous aidera également à tester le bon fonctionnement d’un jeton valide.

 npm install btoa@1.2.1 request-promise@4.2.2

client.js

 require ('dotenv'). Config ()
const demande = require ('request-promise')
const btoa = require ('btoa')

const {ISSUER, CLIENT_ID, CLIENT_SECRET, SCOPE} = process.env

const [,, uri, method, body] = process.argv
si (! uri) {
  console.log ('Utilisation: noeud client {url} [{method}] [{jsonData}]')
  process.exit (1)
}

const sendAPIRequest = async () => {
  const token = btoa (`$ {CLIENT_ID}: $ {CLIENT_SECRET}`)
  essayez {
    const auth = demande en attente ({
      uri: `$ {ISSUER} / v1 / token`,
      json: vrai,
      méthode: 'POST',
      en-têtes: {
        autorisation: `Basic $ {jeton}`
      },
      forme: {
        grant_type: 'client_credentials',
        scope: SCOPE
      }
    })

    réponse const = attendre la demande ({
      uri,
      méthode,
      corps,
      en-têtes: {
        autorisation: `$ {auth.token_type} $ {auth.access_token}`
      }
    })

    console.log (réponse)
  } attraper (erreur) {
    console.log (`Erreur: $ {error.message}`)
  }
}

sendAPIRequest ()

Ici, le code charge les variables de .env dans l'environnement, puis les récupère depuis Node. Node stocke les variables d'environnement dans process.env ( process est une variable globale avec un ensemble de variables et de fonctions utiles.)

 require ('dotenv'). Config ()
// ...
const {ISSUER, CLIENT_ID, CLIENT_SECRET, SCOPE} = process.env
// ...

Ensuite, comme cela sera exécuté à partir de la ligne de commande, vous pouvez utiliser à nouveau le processus pour récupérer les arguments transmis avec process.argv . Cela vous donne un tableau avec tous les arguments passés. Les deux premières virgules sont là sans noms de variables car les deux premiers ne sont pas importants dans ce cas; il s'agira simplement du chemin vers le nœud et du nom du script ( client ou client.js ).

L'URL est requise, ce qui inclurait le noeud final, mais la méthode et les données JSON sont facultatives. La méthode par défaut est GET . Par conséquent, si vous ne faites que récupérer des données, vous pouvez les supprimer. Vous n'auriez pas non plus besoin de charge utile dans ce cas. Si les arguments ne semblent pas corrects, alors le programme sortira avec un message d’erreur et un code de sortie de 1 indiquant une erreur.

 const [,, uri, method, body] = process.argv
si (! uri) {
  console.log ('Utilisation: noeud client {url} [{method}] [{jsonData}]')
  process.exit (1)
}

Le noeud n'autorise pas pour l'attente dans le thread principal, alors pour utiliser la syntaxe async / du nettoyeur, vous devez créer

Si une erreur se produit dans l'une des fonctions en attente ed, la try / catch sera imprimée. à l'écran.

 const sendAPIRequest = async () => {
  essayez {
    // ...
  } attraper (erreur) {
    console.error (`Erreur: $ {error.message}`)
  }
}

sendAPIRequest ()

C'est là que le client envoie une demande au serveur d'autorisation pour obtenir un jeton. Pour autoriser avec le serveur d'autorisation lui-même, vous devez utiliser Basic Auth. L'authentification de base est la même chose que celle utilisée par un navigateur lorsque vous obtenez l'une de ces fenêtres contextuelles intégrées demandant un nom d'utilisateur et un mot de passe. Supposons que votre nom d'utilisateur est AzureDiamond et que votre mot de passe est hunter2 . Votre navigateur les concaténerait alors avec un deux-points (: ), puis les encoderait avec base64 (c'est ce que fait la fonction btoa ) QXp1cmVEaWFtb25kOmh1bnRlcjI = . Il envoie ensuite un en-tête d'autorisation de Basic QXp1cmVEaWFtb25kOmh1bnRlcjI = . Le serveur peut alors décoder le jeton avec base64 pour obtenir le nom d'utilisateur et le mot de passe.

L'autorisation de base n'est pas intrinsèquement sécurisée car facile à décoder, c'est pourquoi https est important -in-the-middle attaque. Ici, l'identifiant client et le secret client sont respectivement le nom d'utilisateur et le mot de passe. C'est aussi pourquoi il est important de garder vos CLIENT_ID et CLIENT_SECRET privés.

Pour OAuth 2.0, vous devez également spécifier le type d'attribution, qui est dans ce cas client_credentials puisque vous envisagez de parler entre deux machines. Vous devez également spécifier la portée. Il y a beaucoup d'autres options qui pourraient être ajoutées ici, mais c'est tout ce dont nous avons besoin pour cette démo.

 const token = btoa (`$ {CLIENT_ID}: $ {CLIENT_SECRET}`)
const auth = demande en attente ({
  uri: `$ {ISSUER} / v1 / token`,
  json: vrai,
  méthode: 'POST',
  en-têtes: {
    autorisation: `Basic $ {jeton}`
  },
  forme: {
    grant_type: 'client_credentials',
    scope: SCOPE
  }
})

Une fois authentifié, vous obtenez un jeton d'accès que vous pouvez envoyer à votre API REST et qui devrait ressembler à Bearer eyJra ... HboUg (le jeton réel est beaucoup plus long que cela - probablement quelque part autour de 800 caractères). Le jeton contient toutes les informations nécessaires à l'API REST pour vérifier qui vous êtes, quand le jeton expirera et toutes sortes d'autres informations, telles que les étendues demandées, l'émetteur et l'ID client utilisé pour demander le jeton. [19659003] La réponse de l’API REST est ensuite imprimée à l’écran.

 réponse const = attente de la demande ({
  uri,
  méthode,
  corps,
  en-têtes: {
    autorisation: `$ {auth.token_type} $ {auth.access_token}`
  }
})

console.log (réponse)

Allez-y et testez-le maintenant. Encore une fois, démarrez l'application avec npm test && node. puis essayez certaines commandes comme suit:

 $ node client http: // localhost: 3000 / parts | json
[
  {
    "id": 1,
    "partNumber": "abc-123",
    "modelNumber": "xyz-789",
    "name": "Alphabet Soup",
    "description": "Soup with letters and numbers in it",
    "createdAt": "2018-08-16T02:22:09.446Z",
    "updatedAt": "2018-08-16T02:22:09.446Z"
  }
]

$ node client http: // localhost: 3000 / parts post '{
  "partNumber": "ban-bd",
  "modelNumber": 1,
  "nom": "pain à la banane",
  "description": "Pain à base de bananes"
} '| json
{
  "id": 2,
  "partNumber": "ban-bd",
  "modelNumber": "1",
  "nom": "pain à la banane",
  "description": "Pain à base de bananes",
  "updatedAt": "2018-08-17T00: 23: 23.341Z",
  "createdAt": "2018-08-17T00: 23: 23.341Z"
}

$ node client http: // localhost: 3000 / parts | json
[
  {
    "id": 1,
    "partNumber": "abc-123",
    "modelNumber": "xyz-789",
    "name": "Alphabet Soup",
    "description": "Soup with letters and numbers in it",
    "createdAt": "2018-08-16T02:22:09.446Z",
    "updatedAt": "2018-08-16T02:22:09.446Z"
  },
  {
    "id": 2,
    "partNumber": "ban-bd",
    "modelNumber": "1",
    "name": "Banana Bread",
    "description": "Bread made from bananas",
    "createdAt": "2018-08-17T00:23:23.341Z",
    "updatedAt": "2018-08-17T00:23:23.341Z"
  }
]

$ node client http: // localhost: 3000 / parts / 1 delete | json
{}

$ node client http: // localhost: 3000 / parts | json
[
  {
    "id": 2,
    "partNumber": "ban-bd",
    "modelNumber": "1",
    "name": "Banana Bread",
    "description": "Bread made from bananas",
    "createdAt": "2018-08-17T00:23:23.341Z",
    "updatedAt": "2018-08-17T00:23:23.341Z"
  }
]

En savoir plus sur les références du client Node et OAuth 2.0 avec Okta

J'espère que vous avez vu comme il est facile de créer une API REST dans Node et de la protéger des utilisateurs non autorisés. Vous pouvez trouver le code pour cet exemple sur GitHub .

Maintenant que vous avez eu la possibilité de créer votre propre projet exemple, consultez certaines de ces excellentes ressources sur Node, OAuth 2.0 et Okta Vous pouvez également parcourir le blog des développeurs Okta pour d'autres articles excellents.

Comme toujours, vous pouvez nous contacter dans les commentaires ci-dessous avec des commentaires ou des questions, ou sur Twitter @oktadev . Nous avons hâte d'avoir de vos nouvelles!






Source link
Quitter la version mobile