Fermer

janvier 15, 2019

Construire une application Web simple avec Express, Angular et GraphQL –


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

Au cours des 10 dernières années environ, le concept d’API REST pour les services Web est devenu la pierre angulaire de la plupart des développeurs Web. Récemment, un nouveau concept est apparu, GraphQL. GraphQL est un langage d'interrogation inventé par Facebook et rendu public en 2015. Au cours des trois dernières années, il a fait sensation. Certains le considèrent comme un nouveau moyen révolutionnaire de créer des API Web. La principale différence entre REST traditionnel et GraphQL est la manière dont les requêtes sont envoyées au serveur. Dans les API REST, vous avez un noeud final différent pour chaque type de ressource et la réponse à la demande est déterminée par le serveur. En utilisant GraphQL, vous n’avez généralement qu’un seul point de terminaison et le client peut indiquer explicitement quelles données doivent être renvoyées. Une seule requête dans GraphQL peut contenir plusieurs requêtes sur le modèle sous-jacent.

Dans ce tutoriel, je vais vous montrer comment développer une application Web GraphQL simple. Le serveur s'exécutera à l'aide de Node and Express et le client sera basé sur Angular 7. Vous verrez à quel point il est facile de préparer le serveur à répondre à différentes requêtes. Cela supprime une grande partie du travail nécessaire par rapport à la mise en œuvre d'API de style REST. Pour donner un exemple, je vais créer un service dans lequel les utilisateurs peuvent parcourir les joueurs et le classement ATP Tennis.

Créez votre serveur Express à l’aide de GraphQL

Je vais commencer par implémenter le serveur. Je supposerai que Node est installé sur votre système et que la commande npm est disponible. J'utiliserai également SQLite pour stocker les données. Pour créer les tables de la base de données et importer les données, je vais utiliser l'outil de ligne de commande sqlite3 . Si sqlite3 n'est pas installé, rendez-vous sur la page de téléchargement SQLite et installez le paquet contenant le shell de ligne de commande .

. démarrer, créer un répertoire qui contiendra le code serveur. J'ai simplement appelé mon serveur / . Dans le répertoire, lancez

 npm init -y

Ensuite, vous devrez initialiser le projet avec tous les packages nécessaires au serveur de base.

 npm install --save express@4.16.4 cors@2.8.4 express-graphql@0.6. 12 graphql@14.0.2 sqlite3@4.0.2

Importer des données sur votre serveur Express

Créons maintenant les tables de la base de données et importons certaines données dans celles-ci. Je vais utiliser les classements de tennis ATP disponibles gratuitement de Jeff Sackmann. Dans certains répertoires de votre système, clonez le référentiel GitHub.

 git clone https://github.com/JeffSackmann/tennis_atp.git

Dans ce didacticiel, je n'utiliserai que deux des fichiers de ce référentiel, atp_players.csv et atp_rankings_current.csv . Dans votre répertoire server / démarrez SQLite.

 sqlite3 tennis.db

Ceci créera un fichier tennis.db qui contiendra les données et vous donnera une invite de ligne de commande dans laquelle vous pourrez taper des commandes SQL. Créons nos tables de base de données. Collez et exécutez ce qui suit dans le shell SQLite3.

 Les lecteurs CREATE TABLE (
  "id" ENTIER,
  TEXTE "prénom_nom",
  TEXTE "nom_du_nom"
  TEXTE "main",
  "anniversaire" ENTIER,
  TEXTE "pays"
)

CREATE TABLE classements (
  "date" ENTIER,
  "rang" ENTIER,
  "joueur" ENTIER,
  "points" ENTIER
)

SQLite vous permet d'importer rapidement des données CSV dans vos tables. Exécutez simplement la commande suivante dans le shell SQLite3:

 .mode csv
.import {PATH_TO_TENNIS_DATA} /atp_players.csv lecteurs
.import {PATH_TO_TENNIS_DATA} /atp_rankings_current.csv classements

Dans ce qui précède, remplacez {PATH_TO_TENNIS_DATA} par le chemin dans lequel vous avez téléchargé le référentiel de données de tennis. Vous venez de créer une base de données contenant tous les joueurs de tennis classés par l’ATP et le classement de tous les joueurs actifs de l’année en cours. Vous êtes prêt à quitter SQLite3.

 .quit

Implémenter Express Server

Implémentons maintenant le serveur. Ouvrez un nouveau fichier index.js le point d'entrée principal de votre application serveur. Commencez par les bases Express et CORS.

 const express = require ('express');
const cors = require ('cors');

const app = express (). use (cors ());

Importez maintenant SQLite et ouvrez la base de données sur le tennis en tennis.db .

 const sqlite3 = require ('sqlite3');
const db = new sqlite3.Database ('tennis.db');

Ceci crée une variable db sur laquelle vous pouvez émettre des requêtes SQL et obtenir des résultats.

Vous êtes maintenant prêt à plonger dans la magie de GraphQL. Ajoutez le code suivant à votre fichier index.js .

 const graphqlHTTP = require ('express-graphql');
const {buildSchema} = require ('graphql');

const schema = buildSchema (`
  tapez Query {
    joueurs (offset: Int = 0, limite: Int = 10): [Player]
    player (id: ID!): Joueur
    classement (classement: Int!): [Ranking]
  }

  tapez Player {
    J'ai fait
    prénom: chaîne
    dernier_nom: chaîne
    main: chaîne
    anniversaire: Int
    pays: String
  }

  type Classement {
    date: Int
    rang: Int
    joueur: joueur
    points: Int
  }
`);

Les deux premières lignes importent graphqlHTTP et buildSchema . La fonction graphqlHTTP se connecte à Express et est capable de comprendre et de répondre aux requêtes GraphQL. Le buildSchema est utilisé pour créer un schéma GraphQL à partir d'une chaîne. Examinons un peu plus en détail la définition du schéma.

Les deux types Player et Ranking correspondent au contenu des tables de la base de données. Ceux-ci seront utilisés comme types de retour aux requêtes GraphQL. Si vous regardez de plus près, vous pouvez voir que la définition de Ranking contient un champ player qui a le type Player . À ce stade, la base de données ne contient qu'un INTEGER qui fait référence à une ligne dans la table des joueurs . La structure de données GraphQL doit remplacer cet entier par le lecteur auquel elle fait référence.

La requête de type définit les requêtes qu'un client est autorisé à effectuer. Dans cet exemple, il y a trois requêtes. joueurs retournent un tableau de joueurs . La liste peut être restreinte par un offset et une limite . Cela permettra la pagination à travers la table des joueurs. La requête player renvoie un seul joueur par son identifiant . La requête rankings renvoie un tableau d'objets Ranking pour un classement de joueur donné.

Pour vous simplifier la vie, créez une fonction utilitaire qui émet une requête SQL et renvoie. une promesse qui se résout lorsque la requête est renvoyée. Cela est utile car l'interface sqlite3 est basée sur des rappels, mais GraphQL fonctionne mieux avec Promises. Dans index.js ajoutez la fonction suivante:

 function query (sql, single) {
  renvoyer une nouvelle promesse ((résoudre, rejeter) => {
    var callback = (err, result) => {
      si (err) {
        renvoyer rejeter (err);
      }
      résoudre (résultat);
    };

    if (single) db.get (sql, rappel);
    else db.all (sql, rappel);
  });
}

Il est maintenant temps de mettre en œuvre les requêtes de base de données qui alimentent les requêtes GraphQL. GraphQL utilise quelque chose appelé rootValue pour définir les fonctions correspondant aux requêtes GraphQL.

 const root = {
  joueurs: args => {
    renvoyer la requête (
      `SELECT * FROM players LIMIT $ {args.offset}, $ {args.limit}`,
      faux
    )
  },
  joueur: args => {
    requête de retour (`SELECT * FROM joueurs WHERE id = '$ {args.id}'`, true);
  },
  classement: args => {
    renvoyer la requête (
      `SELECT r.date, r.rank, r.points,
              p.id, p.first_name, p.last_name, p.hand, p.birthday, p.country
      DE joueurs comme p
      LEFT JOIN les classements AS r
      ON p.id = r.player
      WHERE r.rank = $ {args.rank} `,
      faux
    ) .then (rows =>
      rows.map (result => {
        revenir {
          date: result.date,
          points: result.points,
          rang: result.rank,
          joueur: {
            id: result.id,
            prénom: résultat.nom,
            nom de famille: résultat.nom de famille,
            main: result.hand,
            anniversaire: resultat.anniversaire,
            pays: resultat.country
          }
        };
      })
    )
  }
};

Les deux premières requêtes sont assez simples. Ils consistent en des déclarations simples SELECT . Le résultat est passé tout de suite. La requête rankings est un peu plus compliquée car une instruction LEFT JOIN est nécessaire pour combiner les deux tables de la base de données. Ensuite, le résultat est converti dans la structure de données correcte pour la requête GraphQL. Notez dans toutes ces requêtes comment args contient les arguments passés du client. Vous n'avez aucune raison de vous inquiéter de la vérification des valeurs manquantes, de l'attribution de valeurs par défaut ou de la vérification du type correct. Tout cela est fait pour vous par le serveur GraphQL.

Il ne reste plus qu'à créer une route et à y lier la fonction graphqlHTTP .

 app.use (
  '/ graphql',
  graphqlHTTP ({
    schéma,
    rootValue: root,
    graphiql: true
  })
)

app.listen (4201, err => {
  si (err) {
    retourne console.log (err);
  }
  return console.log ('My Express App à l'écoute sur le port 4201');
});

Le graphiql fournit une interface utilisateur conviviale sur laquelle vous pouvez tester les requêtes sur le serveur.

Pour démarrer le serveur, exécutez:

 node index.js

Ouvrez ensuite votre navigateur et accédez à http: // localhost: 4201 / graphql . Vous verrez un banc d'essai interactif pour les requêtes GraphQL.

 Requête relative au classement GraphQL

Ajoutez votre client Angular 7

Qu'est-ce qu'une application Web sans client? Dans cette section, je vais vous guider dans la mise en œuvre d'une application à une seule page utilisant Angular 7. Pour commencer, créez une nouvelle application Angular. Si ce n’est déjà fait, installez la dernière version de l’outil de ligne de commande angulaire sur votre système.

 npm install -g @ angular / cli @ 7.1.0

Vous devrez peut-être exécuter cette commande avec sudo en fonction de votre système d'exploitation. Vous pouvez maintenant créer une nouvelle application angulaire. Dans un nouveau répertoire, exécutez:

 ng new AngularGraphQLClient

Ceci créera un nouveau répertoire et y installera tous les paquetages nécessaires à une application angulaire. Vous serez invité à poser deux questions. Réponse oui pour inclure le routage dans l'application. Les feuilles de style que j'utiliserai dans ce tutoriel seront de simples CSS.

L'application contiendra trois composants associés au module principal app . Vous pouvez les générer en naviguant dans le répertoire qui vient d'être créé et en exécutant les trois commandes suivantes:

 en cours de génération de composant
ng générer des joueurs
ng générer des composants classement

Ceci créera trois répertoires dans src / app et ajoutera le fichier de code composant .ts le modèle .html et le modèle .css feuille de style pour chaque composant. Pour utiliser GraphQL dans Angular, je vais utiliser la bibliothèque Apollo . Configurer Apollo en mode angulaire est une commande simple.

 Ajouter l'addition apollo-angulaire

Cette commande installera un certain nombre de modules de nœud. Il créera également un module angulaire dans un fichier graphql.module.ts dans le dossier / src / app / et l'importera dans le module principal app . Dans ce fichier, vous verrez la ligne

 const uri = ''; // <- ajoute l'URL du serveur GraphQL ici

Remplacez-le par

 const uri = 'http: // localhost: 4201 / graphql';

Ceci spécifie l'adresse URI à laquelle le service GraphQL peut être trouvé.

Remarque: Si vous souhaitez générer des composants après avoir installé Apollo Angular, vous devez spécifier le module auquel le composant est associé. fait parti. Donc, générer le composant Home ci-dessus deviendrait

 ng générer le composant Home --module app

J'utiliserai le module Forms afin de lier les valeurs aux éléments d'entrée dans le code HTML. Ouvrez src / app / app.module.ts et ajoutez

 import {FormsModule} à partir de '@ angular / forms';

en haut du fichier. Ajoutez ensuite FormsModule au tableau importations de la déclaration @NgModule .

Créez votre mise en page et votre routage en mode angulaire

Now open src /index.html. Ce fichier contient le conteneur HTML dans lequel vivra votre application Angular. Vous aurez besoin de ressources CSS et JavaScript externes pour améliorer la conception de votre application. Ajoutez les lignes suivantes à l'intérieur de la balise . Cela inclura un style minimaliste dans Material Design.

  
  

Ensuite, ouvrez src / app.component.html et remplacez le contenu par le suivant:

home Angular with GraphQL       
        
  
  

Cela crée une structure de base avec une barre supérieure et quelques liens qui chargeront différents composants dans le routeur-outlet . Afin de charger les routes disponibles pour l'application, vous devez modifier le app-routing.module.ts . Au sommet, vous verrez la déclaration du tableau routes .

 const routes: Routes = [];

Remplacez cette ligne par la suivante:

 import {PlayersComponent} de './players/players.component';
importer {HomeComponent} de './home/home.component';
importer {RankingComponent} de './ranking/ranking.component';

routes const: Routes = [
  {
    path: '',
    component: HomeComponent
  },
  {
    path: 'players',
    component: PlayersComponent
  },
  {
    path: 'ranking',
    component: RankingComponent
  }
];

Le routeur sait maintenant quels composants placer dans la prise lorsqu'un itinéraire spécifique est sélectionné. À ce stade, votre application affiche déjà les trois pages et les liens dans la barre supérieure les chargeront dans la zone de contenu de votre application.

Enfin, donnons un style à la page. Dans app.component.css collez le contenu suivant.

 .content {
  rembourrage: 1rem;
  affichage: flex;
  justifier-contenu: centre;
}

Ajouter des composants en angulaire

Vous êtes prêt à implémenter les composants. Commençons par le composant qui permet à l’utilisateur de feuilleter tous les joueurs de tennis de la base de données. Copiez le texte suivant dans le fichier src / app / players / players.component.ts . Je vous expliquerai ensuite la signification de chaque partie de ce fichier.

 import {Component, OnInit} from '@ angular / core';
import {Apollo, QueryRef} depuis 'apollo-angular';
importer le gql de 'graphql-tag';

const PLAYERS_QUERY = gql`
  Interroger les joueurs ($ offset: Int) {
    joueurs (offset: $ offset, limite: 10) {
      identifiant
      Prénom
      nom de famille
      main
      anniversaire
      pays
    }
  }
`;

@Composant({
  sélecteur: 'app-players',
  templateUrl: './players.component.html',
  styleUrls: ['./players.component.css']
})
La classe d'exportation PlayersComponent implémente OnInit {
  page = 1;
  joueurs: any [] = [];

  requête privée: QueryRef ;

  constructeur (privé apollo: Apollo) {}

  ngOnInit () {
    this.query = this.apollo.watchQuery ({
      requête: PLAYERS_QUERY,
      variables: {offset: 10 * this.page}
    });

    this.query.valueChanges.subscribe (result => {
      this.players = result.data && result.data.players;
    });
  }

  mettre à jour() {
    this.query.refetch ({offset: 10 * this.page});
  }

  page suivante() {
    this.page ++;
    this.update ();
  }

  prevPage () {
    if (this.page> 0) this.page--;
    this.update ();
  }
}

Les trois premières lignes de ce fichier contiennent les importations nécessaires à la gestion du composant.

 import {Component, OnInit} from '@ angular / core';
import {Apollo, QueryRef} depuis 'apollo-angular';
importer le gql de 'graphql-tag';

Outre les importations angulaires de base, cela rend disponible Apollo et QueryRef de apollo-angular et gql de ] graphql-tag . Le dernier de ceux-ci est immédiatement utilisé pour créer une requête GraphQL.

 const PLAYERS_QUERY = gql`
  Interroger les joueurs ($ offset: Int) {
    joueurs (offset: $ offset, limite: 10) {
      identifiant
      Prénom
      nom de famille
      main
      anniversaire
      pays
    }
  }
`;

La balise gql prend la chaîne de modèle et la transforme en un objet de requête. La requête définie ici demandera au serveur de renvoyer un tableau de joueurs, contenant tous les champs du joueur. Le paramètre limit fera que le serveur renvoie au plus 10 enregistrements. Le paramètre offset peut être spécifié en tant que paramètre de la requête. Cela permettra de parcourir les lecteurs.

 @Component ({
  sélecteur: 'app-players',
  templateUrl: './players.component.html',
  styleUrls: ['./players.component.css']
})
La classe d'exportation PlayersComponent implémente OnInit {
  page = 0;
  joueurs: any [] = [];

  requête privée: QueryRef ;

  constructeur (privé apollo: Apollo) {}
}

Les propriétés de PlayersComponent spécifient l'état du composant. La page de la propriété stocke la page actuelle dans la liste des joueurs. joueurs contiendront le tableau des joueurs qui seront affichés dans un tableau. Il existe également une variable de requête qui stocke la requête. Cela est nécessaire pour pouvoir extraire à nouveau les données chaque fois que l'utilisateur navigue vers une autre page. Le constructeur injectera la propriété apollo afin que vous puissiez accéder à l'interface GraphQL.

 ngOnInit () {)
  this.query = this.apollo
    .watchQuery ({
      requête: PLAYERS_QUERY,
      variables: {offset: 10 * this.page}
    });

    this.query.valueChanges.subscribe (result => {
      this.players = result.data && result.data.players;
    });
  }

Lors de la phase d’initialisation du cycle de vie du composant, la méthode ngOnInit sera appelée. Il s’agit de l’endroit où le composant Players lancera le chargement des données. Ceci est réalisé par this.apollo.watchQuery . En passant le PLAYERS_QUERY avec une valeur pour le paramètre offset . Vous pouvez maintenant vous abonner à toutes les modifications de données en utilisant valueChanges.subscribe . Cette méthode prend un callback qui va définir le tableau players avec les données obtenues du serveur.

 update () {
  this.query.refetch ({offset: 10 * this.page});
}

page suivante() {
  this.page ++;
  this.update ();
}

prevPage () {
  if (this.page> 0) this.page--;
  this.update ();
}

Pour finir, nextPage et prevPage incrémentent ou décrémentent la propriété page . En appelant la récupération de la requête avec les nouveaux paramètres, une demande de serveur est émise. Lorsque les données sont reçues, le rappel d'abonnement est appelé automatiquement.

Le modèle HTML associé à ce composant est stocké dans players.component.html . Collez-y le contenu suivant:

Prénom Nom Main Anniversaire Pays
{{player.first_name}} 19659107] {{player.last_name}} {{player.last_name}} 19659107] {{player.hand}} {{player.birthday}} {{player.country}}
Page {{page + 1}}   

Ceci affiche une liste des joueurs dans une table. En dessous du tableau, j'ai ajouté des liens de pagination.

Le composant Ranking suit à peu près le même schéma. Le src / app / ranking.component.ts ressemble à ceci:

 import {Component, OnInit} à partir de '@ angular / core';
import {Apollo, QueryRef} depuis 'apollo-angular';
importer le gql de 'graphql-tag';

const RANKINGS_QUERY = gql`
  classement de la requête ($ rank: Int!) {
    classements (rang: $ rank) {
      rendez-vous amoureux
      rang
      points
      joueur {
        Prénom
        nom de famille
      }
    }
  }
`;

@Composant({
  sélecteur: 'app-ranking',
  templateUrl: './ranking.component.html',
  styleUrls: ['./ranking.component.css']
})
La classe d'exportation RankingComponent implémente OnInit {
  rang: nombre = 1;
  classement: tout [];
  requête privée: QueryRef ;

  constructeur (privé apollo: Apollo) {}

  ngOnInit () {
    this.query = this.apollo.watchQuery ({
      requête: RANKINGS_QUERY,
      variables: {rang: Math.round (this.rank)}
    });

    this.query.valueChanges.subscribe (result => {
      this.rankings = result.data && result.data.rankings;
    });
  }

  mettre à jour() {
    return this.query.refetch ({rang: Math.round (this.rank)});
  }
}

Comme vous pouvez le constater, la plupart du code est très similaire à celui de players.component.ts . La définition de RANKINGS_QUERY interroge les joueurs au fil du temps qui occupaient un rang particulier. Notez que la requête ne demande que les prénom_nommés et nom dernier du joueur. Cela signifie que le serveur n'enverra aucune donnée de joueur supplémentaire que le client n'aura pas demandée.

Le modèle du composant de classement contient un champ de texte et un bouton dans lesquels l'utilisateur peut entrer un rang et recharger la page. . En dessous se trouve la table des joueurs. Ceci est le contenu de ranking.component.html .

Rankings

  
Classement Date Points Prénom Nom
{{ranking.rank}} {{rank.date}} à 19659659] {{ranking.points }}       {{ranking.player.first_name}}            {{ranking.player.last_name}}     

Pour démarrer le client, exécutez:

 ng serve

Assurez-vous que le serveur est également en cours d'exécution afin que le client puisse demander des données avec succès.

 Page Classement angulaire

Ajoutez le contrôle d'accès à votre application GraphQL Express + Angular

. Les fonctionnalités importantes de chaque application Web sont l’authentification de l’utilisateur et le contrôle d’accès. Dans cette section, je vais vous guider à travers les étapes nécessaires pour ajouter une authentification à la fois au serveur et à la partie cliente de votre application Angular. C'est souvent la partie la plus ardue de la rédaction d'une application. Utiliser Okta simplifie grandement cette tâche et rend l’authentification sécurisée disponible pour tous les développeurs. Si ce n’est déjà fait, créez un compte développeur avec Okta. Visitez https://developer.okta.com/ et sélectionnez Créer un compte gratuit .

 Page d'inscription à Okta

Remplissez le formulaire et inscrivez-vous. Une fois votre inscription terminée, vous pouvez voir le tableau de bord de votre développeur.

 Tableau de bord Okta

Dans le menu supérieur de votre tableau de bord, sélectionnez Applications puis ajoutez une application en cliquant sur le bouton green Bouton Ajouter une application .

 Le magicien Okta SPA

Vous aurez le choix entre différents types d’application. Vous enregistrez une page unique App . Sur la page suivante, vous verrez les paramètres de votre application. Ici, le numéro de port est pré-rempli à 8080. Angular utilise le port 4200 par défaut. Vous devrez donc modifier le numéro de port en 4200.

 Requête relative au classement GraphQL

Une fois terminé, vous recevrez un ClientId . Vous en aurez besoin dans vos applications client et serveur. Vous aurez également besoin de votre domaine de développement Okta. Voici l'URL que vous voyez en haut de la page lorsque vous êtes connecté à votre tableau de bord pour développeurs Okta.

Sécurisez votre client angulaire

Pour pouvoir utiliser l'authentification Okta avec le client angulaire, vous devez installer la bibliothèque okta-angular . Dans le répertoire de base de votre application client, exécutez la commande suivante:

 npm install @ okta / okta-angular @ 1.0.7 apollo-link-context@1.0.10 --save

Maintenant ouvert src / app / app.module.ts . En haut du fichier, ajoutez l'instruction d'importation.

 import {OktaAuthModule} from '@ okta / okta-angular';

Ajoutez maintenant le module à la liste des importations du module app .

 OktaAuthModule.initAuth ({
  émetteur: 'https: // {yourOktaDomain} / oauth2 / default',
  redirectUri: 'http: // localhost: 4200 / implicit / callback',
  clientId: '{yourClientId}'
});

Vous devrez remplacer le domaine de développement yourOktaDomain que vous voyez dans votre navigateur lorsque vous accédez à votre tableau de bord Okta. Remplacez également votreClientId par l'ID de client obtenu lors de l'enregistrement de votre application. Vous êtes maintenant prêt à utiliser l'authentification Okta dans l'ensemble de votre application. Ensuite, vous allez implémenter la connexion et la déconnexion de l'application. Ouvrez app.component.ts et importez OktaAuthService de okta-angular . Collez le code suivant dans le fichier.

 import {Component, OnInit} from '@ angular / core';
importer {routeur} de '@ angular / router';
importer {OktaAuthService} à partir de '@ okta / okta-angular';

@Composant({
  sélecteur: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
La classe d'exportation AppComponent implémente OnInit {
  titre public = 'Mon application angulaire';
  public isAuthenticated: boolean;

  constructeur (public oktaAuth: OktaAuthService) {
    this.oktaAuth. $ authenticationState.subscribe (
      (isAuthenticated: boolean) => (this.isAuthenticated = isAuthenticated)
    )
  }

  async ngOnInit () {
    this.isAuthenticated = attend this.oktaAuth.isAuthenticated ();
  }

  s'identifier() {
    this.oktaAuth.loginRedirect ();
  }

  Connectez - Out() {
    this.oktaAuth.logout ('/');
  }
}

Le service OktaAuthService est injecté via le constructeur. Il est ensuite utilisé pour définir le drapeau isAuthenticated . La méthode subscribe souscrit une fonction de rappel déclenchée à chaque changement d'état de la connexion. Le isAuthenticated est initialisé pendant la phase ngOnInit pour refléter l'état de connexion au premier chargement de l'application. login et logout gèrent le processus de connexion et de déconnexion. Pour que l'authentification fonctionne, okta-angular utilise une route spéciale appelée implicit / callback . Dans le fichier app-routing.module.ts ajoutez l'importation suivante:

 import {OktaCallbackComponent, OktaAuthGuard} à partir de '@ okta / okta-angular';

La route implicite / callback est maintenant liée au tableau OktaCallbackComponent en ajoutant ce qui suit au tableau .

 {.
  chemin: 'implicite / rappel',
  composant: OktaCallbackComponent
}

C'est tout ce dont vous avez besoin pour vous connecter et vous déconnecter. Mais l'application n'est pas encore protégée. Pour tout itinéraire pour lequel vous souhaitez contrôler l'accès, vous devrez ajouter une protection d'autorisation. Heureusement c'est facile. Dans chacune des routes que vous souhaitez protéger, ajoutez la propriété canActivate . Ajoutez ce qui suit aux joueurs et aux classements classés.

 pouvez activer: [OktaAuthGuard];

C’est tout. Désormais, lorsqu'un utilisateur essaiera d'accéder à la vue Joueurs, il sera redirigé vers la page de connexion Okta. Une fois connecté, l'utilisateur sera redirigé vers la vue Produits.

Vous avez sécurisé les pages client, mais avant de pouvoir passer à la sécurisation du back-end, prenons un moment pour réfléchir à la manière dont le serveur authentifiera l'utilisateur. . Okta utilise un jeton porteur identifiant l'utilisateur. Le jeton porteur doit être envoyé au serveur avec chaque demande. Pour ce faire, le client doit s'assurer que le jeton de support est ajouté aux en-têtes HTTP. Tout ce que vous avez à faire est d’ajouter quelques lignes de code au graphql.module.ts . En haut du fichier, importez ce qui suit:

 import {OktaAuthService} de '@ okta / okta-angular';
importer {setContext} de 'apollo-link-context';

Modifiez ensuite la fonction createApollo pour ajouter le jeton porteur.

fonction d'exportation createApollo (httpLink: HttpLink, oktaAuth: OktaAuthService) {
  const http = httpLink.create ({uri});

  const auth = setContext ((_, {headers}) => {
    retourne oktaAuth.getAccessToken (). then (token => {
      retour jeton? {en-têtes: {Autorisation: `Porteur $ {jeton}`}}: {};
    });
  });

  revenir {
    lien: auth.concat (http),
    cache: new InMemoryCache ()
  };
}

Sécurisez votre serveur Express GraphQL

La sécurisation du serveur se fait en ajoutant une fonction de middleware express à l'application serveur. Pour ce faire, vous aurez besoin de quelques bibliothèques supplémentaires. Accédez au répertoire de votre serveur et exécutez la commande

 npm install @ okta / jwt-verifier @ 0.0.13 body-parser@1.18.3 express-bearer-token@2.2.0

Ensuite, créons cette fonction dans un fichier séparé appelé auth.js dans le dossier racine du serveur.

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

const oktaJwtVerifier = new OktaJwtVerifier ({
  clientId: '{yourClientId}',
  émetteur: 'https: // {yourOktaDomain} / oauth2 / default'
});

module.exports = fonction asynchrone oktaAuth (req, res, next) {
  essayer {
    jeton const = req.token;
    si (! jeton) {
      return res.status (401) .send ('Non autorisé');
    }
    const jwt = wait oktaJwtVerifier.verifyAccessToken (jeton);
    req.user = {
      uid: jwt.claims.uid,
      email: jwt.claims.sub
    };
    suivant();
  } catch (err) {
    return res.status (401) .send (err.message);
  }
};

Encore une fois, vous devez remplacer yourOktaDomain et yourClientId par le domaine de développement et l'identifiant du client. Le but de cette fonction est simple. Il vérifie la présence d'un champ de jeton dans la demande. S'il est présent, oktaJwtVerifier vérifie la validité du jeton. Si tout est en ordre, appeler next () signale le succès. Sinon, une erreur 401 est renvoyée. Il ne vous reste plus qu'à vous assurer que la fonction est utilisée dans l'application. Ajoutez les instructions require suivantes au fichier index.js .

 const bodyParser = require ('body-parser');
const bearerToken = require ('express-bearer-token');
const oktaAuth = require ('./ auth');

Modifiez ensuite la déclaration de app de la manière suivante:

 const app = express ()
  .use (cors ())
  .use (bodyParser.json ())
  .use (bearerToken ())
  .use (oktaAuth);

Le middleware bearerToken va rechercher un jeton porteur et l'ajouter à la demande de recherche de oktaAuth . Grâce à cet ajout simple, votre serveur autorisera uniquement les requêtes fournissant une authentification valide.

En savoir plus sur Express, Angular et GraphQL

Dans ce tutoriel simple, je vous ai montré comment créer une application à une seule page avec Angular. en utilisant GraphQL. L'authentification utilisateur a été mise en œuvre avec un minimum d'effort à l'aide du service Okta.

Je n'ai pas expliqué comment utiliser GraphQL pour ajouter ou modifier les données de la base de données. In GraphQL language this is called mutations. To learn more about mutations using Apollo, check out the manual pages.

The complete code for this project can be found at https://github.com/oktadeveloper/okta-graphql-angular-example.

If you’re interested in learning more about Express, Angular, GraphQL, or secure user management, I’d encourage you to check out any of these resources:

Like what you learned today? We’d love to have you follow us on Twitter and subscribe to our YouTube channel!






Source link