GraphQL - Authentifizierungsclient
Authentifizierung ist der Prozess oder die Aktion zum Überprüfen der Identität eines Benutzers oder eines Prozesses. Es ist wichtig, dass eine Anwendung einen Benutzer authentifiziert, um sicherzustellen, dass die Daten einem anonymen Benutzer nicht zur Verfügung stehen. In diesem Abschnitt erfahren Sie, wie Sie einen GraphQL-Client authentifizieren.
Express JWT
In diesem Beispiel verwenden wir jQuery, um eine Clientanwendung zu erstellen. Zur Authentifizierung von Anfragen verwenden wir express-jwt Modul auf der Serverseite.
Das Express-JWT-Modul ist eine Middleware, mit der Sie HTTP-Anforderungen mithilfe von JWT-Token authentifizieren können. JSON Web Token (JWT) ist eine lange Zeichenfolge, die den angemeldeten Benutzer identifiziert.
Sobald sich der Benutzer erfolgreich angemeldet hat, generiert der Server ein JWT-Token. Dieses Token identifiziert ein Protokoll eindeutig. Mit anderen Worten, das Token ist eine Darstellung der Benutzeridentität. Wenn der Client das nächste Mal zum Server kommt, muss er dieses Token vorlegen, um die erforderlichen Ressourcen zu erhalten. Der Client kann entweder eine mobile Anwendung oder eine Webanwendung sein.
Illustration
Wir werden schrittweise vorgehen, um diese Abbildung zu verstehen.
Server einrichten
Im Folgenden finden Sie die Schritte zum Einrichten des Servers:
Schritt 1 - Laden Sie die erforderlichen Abhängigkeiten für das Projekt herunter und installieren Sie sie
Erstellen Sie einen Ordner auth-server-app. Ändern Sie Ihr Verzeichnis in auth-server-app vom Terminal. Befolgen Sie die Schritte 3 bis 5, die im Kapitel Umgebungs-Setup erläutert werden.
Schritt 2 - Erstellen Sie ein Schema
Hinzufügen schema.graphql Datei im Projektordner auth-server-app und fügen Sie den folgenden Code hinzu -type Query
{
greetingWithAuth:String
}
Schritt 3 - Resolver hinzufügen
Erstellen Sie eine Datei resolvers.js im Projektordner und fügen Sie den folgenden Code hinzu -
Der Resolver überprüft, ob ein authentifiziertes Benutzerobjekt im Kontextobjekt von GraphQL verfügbar ist. Es wird eine Ausnahme ausgelöst, wenn kein authentifizierter Benutzer verfügbar ist.
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}
Schritt 4 - Server.js-Datei erstellen
Die Authentifizierungs-Middleware authentifiziert Anrufer mithilfe eines JSON-Web-Tokens. Die URL für die Authentifizierung lautet http://localhost:9000/login.
Dies ist eine Nachoperation. Der Benutzer muss seine E-Mail-Adresse und sein Passwort eingeben, die vom Backend bestätigt werden. Wenn ein gültiges Token mit der Methode jwt.sign generiert wird, muss der Client dieses für nachfolgende Anforderungen im Header senden.
Wenn das Token gültig ist, wird req.user mit dem JSON-Objekt festgelegt, das dekodiert wurde, um von der späteren Middleware für die Autorisierung und Zugriffskontrolle verwendet zu werden.
Der folgende Code verwendet zwei Module - jsonwebtoken und express-jwt zur Authentifizierung von Anforderungen -
Wenn der Benutzer auf klickt greetSchaltfläche wird eine Anforderung für die / graphql-Route ausgegeben. Wenn der Benutzer nicht authentifiziert ist, wird er aufgefordert, sich selbst zu authentifizieren.
Dem Benutzer wird ein Formular angezeigt, in dem die E-Mail-ID und das Kennwort akzeptiert werden. In unserem Beispiel ist die / login-Route für die Authentifizierung des Benutzers verantwortlich.
Die Route / login überprüft, ob in der Datenbank eine Übereinstimmung für die vom Benutzer bereitgestellten Anmeldeinformationen gefunden wurde.
Wenn die Anmeldeinformationen ungültig sind, wird eine HTTP 401-Ausnahme an den Benutzer zurückgegeben.
Wenn die Anmeldeinformationen gültig sind, wird vom Server ein Token generiert. Dieses Token wird als Teil der Antwort an den Benutzer gesendet. Dies erfolgt durch die Funktion 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});
});
Für jede Anfrage wird die Funktion app.use () aufgerufen. Dies ruft wiederum die ExpressJWT-Middleware auf. Diese Middleware dekodiert das JSON-Web-Token. Die im Token gespeicherte Benutzer-ID wird abgerufen und als Eigenschaftsbenutzer im Anforderungsobjekt gespeichert.
//decodes the JWT and stores in request object
app.use(expressJwt({
secret: jwtSecret,
credentialsRequired: false
}));
Um die Benutzereigenschaft im GraphQL-Kontext verfügbar zu machen, wird diese Eigenschaft der zugewiesen context Objekt wie unten gezeigt -
//Make req.user available to GraphQL context
app.use('/graphql', graphqlExpress((req) => ({
schema,
context: {user: req.user &&apm; db.students.get(req.user.sub)}
})));
Erstellen server.js im aktuellen Ordnerpfad. Die vollständige Datei server.js lautet wie folgt:
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}`));
Schritt 5 - Führen Sie die Anwendung aus
Führen Sie den Befehl npm start im Terminal aus. Der Server ist am 9000-Port betriebsbereit. Hier verwenden wir GraphiQL als Client, um die Anwendung zu testen.
Öffnen Sie den Browser und geben Sie die URL ein http://localhost:9000/graphiql. Geben Sie die folgende Abfrage in den Editor ein -
{
greetingWithAuth
}
In der folgenden Antwort ist ein Fehler aufgetreten, da wir kein authentifizierter Benutzer sind.
{
"data": {
"greetingWithAuth": null
},
"errors": [
{
"message": "Unauthorized",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"greetingWithAuth"
]
}
]
}
Lassen Sie uns im nächsten Abschnitt eine Clientanwendung zur Authentifizierung erstellen.
Einrichten des JQuery-Clients
In der Clientanwendung wird eine Begrüßungsschaltfläche bereitgestellt, die das Schema aufruft greetingWithAuth. Wenn Sie auf die Schaltfläche ohne Anmeldung klicken, wird die folgende Fehlermeldung angezeigt:
Sobald Sie sich mit einem in der Datenbank verfügbaren Benutzer angemeldet haben, wird der folgende Bildschirm angezeigt:
Zugreifen greetingmüssen wir zuerst auf die URL zugreifen http://localhost:9000/login Route wie unten.
Die Antwort enthält das vom Server generierte Token.
$.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')
})
Nach einer erfolgreichen Anmeldung können wir wie unten angegeben auf das Schema greetingWithAuth zugreifen . Für alle nachfolgenden Anfragen mit Inhaber-Token sollte ein Authorizationheader vorhanden sein.
{
url: "http://localhost:9000/graphql",
contentType: "application/json",
headers: {"Authorization": 'bearer '+loginToken}, type:'POST',
data: JSON.stringify({
query:`{greetingWithAuth}`
}
Das Folgende ist der Code für 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>