GraphQL - Authentification du client
L'authentification est le processus ou l'action de vérification de l'identité d'un utilisateur ou d'un processus. Il est important qu'une application authentifie un utilisateur pour s'assurer que les données ne sont pas disponibles pour un utilisateur anonyme. Dans cette section, nous apprendrons comment authentifier un client GraphQL.
Express JWT
Dans cet exemple, nous utiliserons jQuery pour créer une application cliente. Pour authentifier les demandes, nous utiliserons express-jwt module côté serveur.
Le module express-jwt est un middleware qui vous permet d'authentifier les requêtes HTTP à l'aide de jetons JWT. JSON Web Token (JWT) est une longue chaîne qui identifie l'utilisateur connecté.
Une fois que l'utilisateur se connecte avec succès, le serveur génère un jeton JWT. Ce jeton identifie distinctement un journal. En d'autres termes, le jeton est une représentation de l'identité de l'utilisateur. Ainsi, la prochaine fois, lorsque le client arrive sur le serveur, il doit présenter ce jeton pour obtenir les ressources nécessaires. Le client peut être une application mobile ou une application Web.
Illustration
Nous suivrons une procédure par étapes pour comprendre cette illustration.
Configuration du serveur
Voici les étapes de configuration du serveur -
Étape 1 - Téléchargez et installez les dépendances requises pour le projet
Créer un dossier auth-server-app. Changez votre répertoire en auth-server-app depuis le terminal. Suivez les étapes 3 à 5 expliquées dans le chapitre Configuration de l'environnement.
Étape 2 - Créer un schéma
Ajouter schema.graphql fichier dans le dossier du projet auth-server-app et ajoutez le code suivant -type Query
{
greetingWithAuth:String
}
Étape 3 - Ajouter des résolveurs
Créer un fichier resolvers.js dans le dossier du projet et ajoutez le code suivant -
Le résolveur vérifiera si un objet utilisateur authentifié est disponible dans l'objet de contexte de GraphQL. Cela déclenchera une exception si un utilisateur authentifié n'est pas disponible.
const db = require('./db')
const Query = {
greetingWithAuth:(root,args,context,info) => {
//check if the context.user is null
if (!context.user) {
throw new Error('Unauthorized');
}
return "Hello from TutorialsPoint, welcome back : "+context.user.firstName;
}
}
module.exports = {Query}
Étape 4 - Créer un fichier Server.js
L'intergiciel d'authentification authentifie les appelants à l'aide d'un jeton Web JSON. L'URL pour l'authentification est http://localhost:9000/login.
Ceci est une opération post. L'utilisateur doit soumettre son email et son mot de passe qui seront validés depuis le backend. Si un jeton valide est généré à l'aide de la méthode jwt.sign, le client devra l'envoyer dans l'en-tête pour les demandes suivantes.
Si le jeton est valide, req.user sera défini avec l'objet JSON décodé pour être utilisé par un middleware ultérieur pour l'autorisation et le contrôle d'accès.
Le code suivant utilise deux modules - jsonwebtoken et express-jwt pour authentifier les requêtes -
Lorsque l'utilisateur clique sur le greetbouton, une requête pour la route / graphql est émise. Si l'utilisateur n'est pas authentifié, il sera invité à s'authentifier.
L'utilisateur reçoit un formulaire qui accepte l'identifiant et le mot de passe de messagerie. Dans notre exemple, la route / login est responsable de l'authentification de l'utilisateur.
La route / login vérifie si une correspondance est trouvée dans la base de données pour les informations d'identification fournies par l'utilisateur.
Si les informations d'identification ne sont pas valides, une exception HTTP 401 est renvoyée à l'utilisateur.
Si les informations d'identification sont valides, un jeton est généré par le serveur. Ce jeton est envoyé dans le cadre de la réponse à l'utilisateur. Ceci est fait par la fonction jwt.sign.
const expressJwt = require('express-jwt');
const jwt = require('jsonwebtoken');
//private key
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
app.post('/login', (req, res) => {
const {email, password} = req.body;
//check database
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
//generate a token based on private key, token doesn't have an expiry
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
Pour chaque requête, la fonction app.use () sera appelée. Cela invoquera à son tour le middleware expressJWT. Ce middleware décodera le jeton Web JSON. L'ID utilisateur stocké dans le jeton sera récupéré et stocké en tant qu'utilisateur de propriété dans l'objet de requête.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Pour rendre disponible la propriété utilisateur dans le contexte GraphQL, cette propriété est affectée au context objet comme indiqué ci-dessous -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Créer server.js dans le chemin du dossier actuel. Le fichier server.js complet est le suivant -
const bodyParser = require('body-parser');
const cors = require('cors');
const express = require('express');
const expressJwt = require('express-jwt'); //auth
const jwt = require('jsonwebtoken'); //auth
const db = require('./db');
var port = process.env.PORT || 9000
const jwtSecret = Buffer.from('Zn8Q5tyZ/G1MHltc4F/gTkVJMlrbKiZt', 'base64');
const app = express();
const fs = require('fs')
const typeDefs = fs.readFileSync('./schema.graphql',{encoding:'utf-8'})
const resolvers = require('./resolvers')
const {makeExecutableSchema} = require('graphql-tools')
const schema = makeExecutableSchema({typeDefs, resolvers})
app.use(cors(), bodyParser.json(), expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
const {graphiqlExpress,graphqlExpress} = require('apollo-server-express')
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user && db.students.get(req.user.sub)}
})));
app.use('/graphiql',graphiqlExpress({endpointURL:'/graphql'}))
//authenticate students
app.post('/login', (req, res) => {
const email = req.body.email;
const password = req.body.password;
const user = db.students.list().find((user) => user.email === email);
if (!(user && user.password === password)) {
res.sendStatus(401);
return;
}
const token = jwt.sign({sub: user.id}, jwtSecret);
res.send({token});
});
app.listen(port, () => console.info(`Server started on port ${port}`));
Étape 5 - Exécutez l'application
Exécutez la commande npm start dans le terminal. Le serveur sera opérationnel sur le port 9000. Ici, nous utilisons GraphiQL comme client pour tester l'application.
Ouvrez le navigateur et saisissez l'URL http://localhost:9000/graphiql. Tapez la requête suivante dans l'éditeur -
{
greetingWithAuth
}
Dans la réponse ci-dessous, nous avons obtenu une erreur car nous ne sommes pas un utilisateur authentifié.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
Dans la section suivante, créons une application client pour s'authentifier.
Configuration du client JQuery
Dans l'application cliente, un bouton de bienvenue est fourni qui invoquera le schéma greetingWithAuth. Si vous cliquez sur le bouton sans connexion, cela vous donnera le message d'erreur ci-dessous -
Une fois que vous vous connectez avec un utilisateur disponible dans la base de données, l'écran suivant apparaîtra -
Accéder greeting, nous devons d'abord accéder à l'URL http://localhost:9000/login itinéraire comme ci-dessous.
La réponse contiendra le jeton généré par le serveur.
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
.html("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
Après une connexion réussie, nous pouvons accéder à greetingWithAuth schéma comme indiqué ci - dessous. Il devrait y avoir un en-tête d'autorisation pour toutes les demandes suivantes avec un jeton de support.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
Ce qui suit est le code pour index.html -
<!DOCTYPE html>
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
let loginToken = "";
$("#btnGreet").click(function() {
$.ajax({url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken},
type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}` }),
success: function(result) {
$("#greetingDiv").html("<h1>"+result.data.greetingWithAuth+"</h1>")
},
error:function(jQxhr,error) {
if(jQxhr.status == 401) {
$("#greetingDiv").html('please authenticate first!!')
.css({"color":"red",'font-weight':'bold'})
return;
}
$("#greetingDiv").html('error').css("color","red");
}
});
});
$('#btnAuthenticate').click(function() {
var email = $("#txtEmail").val();
var password = $("#txtPwd").val();
if(email && password) {
$.ajax({
url:"http://localhost:9000/login",
contentType:"application/json",
type:"POST",
data:JSON.stringify({email,password}),
success:function(response) {
loginToken = response.token;
$('#authStatus')
.html("authenticated successfully")
.css({"color":"green",'font-weight':'bold'});
$("#greetingDiv").html('').css({'color':''});
},
error:(xhr,err) => alert('error')
})
}else alert("email and pwd empty")
})
});
</script>
</head>
<body>
<h1> GraphQL Authentication </h1>
<hr/>
<section>
<button id = "btnGreet">Greet</button>
<br/> <br/>
<div id = "greetingDiv"></div>
</section>
<br/> <br/> <br/>
<hr/>
<section id = "LoginSection">
<header>
<h2>*Login first to access greeting </h2>
</header>
<input type = "text" value = "[email protected]" placeholder = "enter email" id = "txtEmail"/>
<br/>
<input type = "password" value = "pass123" placeholder = "enter password" id = "txtPwd"/>
<br/>
<input type = "button" id = "btnAuthenticate" value = "Login"/>
<p id = "authStatus"></p>
</section>
</body>
</html>