{"id":1935,"date":"2019-10-15T00:00:27","date_gmt":"2019-10-14T22:00:27","guid":{"rendered":"https:\/\/webdeasy.de\/?p=1935"},"modified":"2024-06-09T15:31:36","modified_gmt":"2024-06-09T13:31:36","slug":"nodejs-login-system","status":"publish","type":"post","link":"https:\/\/webdeasy.de\/nodejs-login-system\/","title":{"rendered":"Node.js Login System (mit Express, JWT &amp; MySQL)"},"content":{"rendered":"\n<p class=\"has-drop-cap\">In diesem Tutorial bauen wir ein Node.js Login System mit allen Basic Funktionen. Dazu nutzen wir Express, MySQL und JWT .<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>Wir bauen ein komplettes Login System in Node.js, welches du einfach in ein beliebiges Frontend (React, Angular, Vue.js, &#8230;) einbinden kannst. Das ist m\u00f6glich, da wir das komplette Node.js Login System als Rest API umsetzen.<\/p>\n\n\n\n<p class=\"info-notice info\">Dieser Blogpost ist Teil 1 meiner zweiteiligen Tutorial-Reihe. In Teil 2 (am Ende verlinkt) bauen wir zusammen das passende Frontend.<\/p>\n\n\n\n<p>Als Bonus stelle ich dir den kompletten Code in einem Git Repository bereit! \ud83d\ude42<\/p>\n\n\n<div class='table-of-contents'><span class='toc-headline'>Inhaltsverzeichnis<\/span><!-- Table of contents by webdeasy.de --><span class='toggle-toc custom-setting' title='zuklappen'>\u2212<\/span><\/div><div id='ezoic-pub-ad-placeholder-622'><\/div>\n\n\n\n<p><strong>Das wirst du in diesem Tutorial lernen:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Erstellen eine Node.js Projektes und Installation aller ben\u00f6tigen NPM Packages.<\/li>\n\n\n\n<li>Entwerfen einer sinnvollen Node.js Backend Struktur.<\/li>\n\n\n\n<li>Herstellen einer Datenbankverbindung und Ausf\u00fchren von Operationen auf der MySQL Datenbank.<\/li>\n\n\n\n<li>Implementieren mehrere Routen mit POST und GET in Node.js und Express.<\/li>\n\n\n\n<li>Erstellen und Validieren von Sessions mit JWT, um zu \u00fcberpr\u00fcfen ob ein Nutzer angemeldet ist.<\/li>\n<\/ul>\n\n\n\n<p><strong>Welche Komponenten ben\u00f6tigen wir f\u00fcr unser Node.js Login System?<\/strong><\/p>\n\n\n\n<p>Wir nutzen eine MySQL Datenbank, in der unsere Benutzerdaten gespeichert werden. Alternativ kannst du die Datenbank aber auch durch z.B. eine <a href=\"https:\/\/www.mongodb.com\/de-de\" target=\"_blank\" rel=\"noreferrer noopener\">MongoDB<\/a> Datenbank ersetzen. Zur Authentifizierung m\u00fcssen wir diese Daten dann abfragen und k\u00f6nnen mit Hilfe des <a href=\"https:\/\/jwt.io\/\" target=\"_blank\" rel=\"noreferrer noopener\">JWT (JSON Web Token)<\/a> Packages eine Session (Sitzung) f\u00fcr den Benutzer er\u00f6ffnen. Zur Umsetzung der Rest API nutzen wir das <a href=\"https:\/\/www.npmjs.com\/package\/express\" target=\"_blank\" rel=\"noreferrer noopener\">Express<\/a> Framework.<\/p>\n\n\n\n<p><strong>Hier gibt es das Tutorial auch in Videoform:<\/strong><\/p>\n\n\n\n<iframe loading=\"lazy\" width=\"560\" height=\"315\" src=\"https:\/\/www.youtube-nocookie.com\/embed\/41pbn2I_XkY\" title=\"YouTube video player\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"\"><\/iframe>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"restapi\">1. Node.js Projekt aufsetzen und NPM Packages installieren<\/h2>\n\n\n\n<p>Nachdem du ein neues Projekt mit <code>npm init<\/code> initialisiert hast, k\u00f6nnen wir die ben\u00f6tigten Abh\u00e4ngigkeiten installieren. Wir ben\u00f6tigen folgende Module: <\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th>Package<\/th><th>Beschreibung<\/th><\/tr><\/thead><tbody><tr><td><strong>express<\/strong><\/td><td>Damit erstellen wir unseren eigenen Webserver f\u00fcr unsere Rest API<\/td><\/tr><tr><td><strong>mysql2<\/strong><\/td><td>Zum Lesen\/Schreiben in unsere Datenbank<\/td><\/tr><tr><td><strong>uuid<\/strong><\/td><td>Zum Erstellen von IDs f\u00fcr sp\u00e4tere Benutzer<\/td><\/tr><tr><td><strong>bcryptjs (Achtung: <\/strong><span style=\"text-decoration: underline;\"><strong>nicht<\/strong><\/span><strong> bcrypt)<\/strong><\/td><td>Zum Hashen der Passw\u00f6rter<\/td><\/tr><tr><td><strong>jsonwebtoken<\/strong><\/td><td>Zur Handhabung der Nutzer-Sessions<\/td><\/tr><tr><td><strong>cors<\/strong><\/td><td>Damit wir die Rest API von unserer Website aufrufen k\u00f6nnen<\/td><\/tr><tr><td><strong>dotenv<\/strong><\/td><td>Verwalten von Umgebungsvariablen<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Diese Module installieren wir \u00fcber folgenden CLI Befehl:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"bash\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">npm install express mysql2 uuid bcryptjs jsonwebtoken cors dotenv<\/pre>\n\n\n\n<p>Damit du einen besser \u00dcberblick hast, wo welche Dateien abzulegen sind, hier eine kleine \u00dcbersicht:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\u251c\u2500\u2500 lib\n\u2502   \u2514\u2500\u2500 db.js\n\u251c\u2500\u2500 middleware\n\u2502   \u2514\u2500\u2500 users.js\n\u251c\u2500\u2500 routes\n\u2502   \u2514\u2500\u2500 router.js\n\u251c\u2500\u2500 .env\n\u2514\u2500\u2500 index.js<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"database\">2. MySQL Datenbank einrichten<\/h2>\n\n\n\n<p>Um die Benutzerdaten, also Benutzername, Passwort, etc. in unserem Node.js Login System zu speichern ben\u00f6tigen wir eine Datenbank &#8211; in unsere Fall MySQL. Als Datenbank-Engine nutze ich <a aria-label=\"XAMPP, (\u00f6ffnet in neuem Tab)\" href=\"https:\/\/www.apachefriends.org\/de\/index.html\" target=\"_blank\" rel=\"noreferrer noopener\">XAMPP,<\/a> damit ich mir eine eigene Datenbank lokal hosten kann. Nat\u00fcrlich kannst du auch jede andere (Remote-) Datenbank verwenden oder eine lokale Datenbank mit <a href=\"https:\/\/webdeasy.de\/docker-vs-vm\/\">Docker<\/a> starten.<\/p>\n\n\n\n<p>F\u00fcr unser Login System ben\u00f6tigen wir nur eine Tabelle nach folgendem Schema:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"437\" height=\"263\" src=\"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/image.jpg\" alt=\"ER-Modell der &quot;users&quot; Tabelle\" class=\"wp-image-2057\"\/><figcaption class=\"wp-element-caption\">ER-Modell der &#8222;users&#8220; Tabelle<\/figcaption><\/figure>\n\n\n\n<p>Das Attribut &#8222;id&#8220; nutzen wir als Primary Key und aktivieren die Auto-Increment Funktion.<br>In der Datenbank sieht unsere Tabelle dann folgenderma\u00dfen aus:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"523\" height=\"180\" src=\"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/node-jwt-db.png\" alt=\"phpMyAdmin Ansicht der &quot;users&quot; Tabelle\" class=\"wp-image-2059\"\/><figcaption class=\"wp-element-caption\">phpMyAdmin Ansicht der &#8222;users&#8220; Tabelle<\/figcaption><\/figure>\n\n\n\n<p>Damit wir Daten in Node.js aus unserer Datenbank abrufen k\u00f6nnen, erstellen wir eine eigene Datei, die wir sp\u00e4ter in unserem Express Router einbinden.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ lib\/db.js\n\nconst mysql = require('mysql2');\n\nconst connection = mysql.createConnection({\n  host: process.env.DB_HOST,\n  user: process.env.DB_USER,\n  database: process.env.DB_NAME,\n  password: process.env.DB_PASSWORD,\n});\n\nconnection.connect();\nmodule.exports = connection;<\/pre>\n\n\n\n<p><strong>Sicherheitsrelevante Informationen, wie Passw\u00f6rter, PINs oder Tokens solltest du niemals direkt im Code speichern! <\/strong>Daher legt man f\u00fcr solche Daten Umgebungsvariablen an. Das sind Variablen, die in den verschiedenen Stages deiner Anwendung unterschiedlich konfiguriert sein k\u00f6nnen und auch niemals in einem Repository gespeichert werden.<\/p>\n\n\n\n<p>Um diese Platzhalter nun mit dem richtigen Inhalt zu f\u00fcllen, legen wir die Datei <code>.env<\/code> an. Beachte den Punkt am Anfang. Dort legen wir unsere vier verwendeten Variablen an:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">DB_HOST=localhost\nDB_USER=root\nDB_PASSWORD=******\nDB_NAME=node-login-tutorial<\/pre>\n\n\n\n<p class=\"info-notice warning\">Wenn du deinen Code in einem Repository verwaltest, solltest du unbedingt die Datei <code>.env<\/code> in deiner <code>.gitignore<\/code> einf\u00fcgen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"router\">3. Express aufsetzen und Routen erstellen<\/h2>\n\n\n\n<p>Unsere Einstiegsdatei ist die <code>index.js<\/code> und beinhaltet das Starten unsere Webservers und die Einbindung der Routen, die wir in der Datei <code>routes\/router.js<\/code> definieren.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ index.js\n\nconst express = require('express');\nconst app = express();\nconst cors = require('cors');\n\nrequire('dotenv').config();\nconst PORT = process.env.PORT || 3000;\n\napp.use(express.json());\napp.use(cors());\n\nconst router = require('.\/routes\/router.js');\napp.use('\/api', router);\n\napp.listen(PORT, () => console.log(`Server running on port ${PORT}`));<\/pre>\n\n\n\n<p>Das ist unsere Hauptdatei, daher gehen wir Zeile f\u00fcr Zeile durch was hier passiert.<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><thead><tr><th>Zeile<\/th><th>Beschreibung<\/th><\/tr><\/thead><tbody><tr><td>Zeile 3<\/td><td>Importiert das <strong>express<\/strong> Modul<\/td><\/tr><tr><td>Zeile 4<\/td><td>Erstellt eine Instanz der Express-Anwendung<\/td><\/tr><tr><td>Zeile 5<\/td><td>Importiert das <strong>cors<\/strong> Modul<\/td><\/tr><tr><td>Zeile 7<\/td><td>L\u00e4dt Umgebungsvariablen aus der <code>.env<\/code>-Datei<\/td><\/tr><tr><td>Zeile 8<\/td><td>Setzt den Port auf den in der Umgebungsvariablen definierten Wert oder auf 3000, falls dieser nicht definiert ist<\/td><\/tr><tr><td>Zeile 10<\/td><td>Konfiguriert die Anwendung, um JSON-formatierte Anfragen zu parsen<\/td><\/tr><tr><td>Zeile 11<\/td><td>Aktiviert CORS f\u00fcr die Anwendung<\/td><\/tr><tr><td>Zeile 13-14<\/td><td>Importiert den Router aus der Datei <code>router.js<\/code> im Verzeichnis <code>routes<\/code> und verwendet den importierten Router f\u00fcr alle Routen, die mit <code>\/api<\/code> beginnen<\/td><\/tr><tr><td>Zeile 16<\/td><td>Startet den Server und gibt eine Nachricht in der Konsole aus, dass der Server auf dem definierten Port l\u00e4uft<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>In der <code>router.js<\/code> definieren wir unsere Routen und verpacken danach die Logik darin. Grund, wieso wir hier eine extra Datei benutzen ist die \u00dcbersichtlichkeit. Wenn Deine Anwendung irgendwann 20 oder noch mehr Routen hat, gibt es ein gro\u00dfes Chaos in der <code>index.js<\/code>. Deshalb lagern wir unsere Routen aus.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/router.js\n\nconst express = require('express');\nconst router = express.Router();\n\nconst bcrypt = require('bcryptjs');\nconst uuid = require('uuid');\nconst jwt = require('jsonwebtoken');\n\nconst db = require('..\/lib\/db.js');\nconst userMiddleware = require('..\/middleware\/users.js');\n\nrouter.post('\/sign-up', (req, res, next) => {});\n\nrouter.post('\/login', (req, res, next) => {});\n\nrouter.get('\/secret-route', (req, res, next) => {\n  res.send('This is the secret content. Only logged in users can see that!');\n});\n\nmodule.exports = router;<\/pre>\n\n\n\n<p>Hier registrieren wir die Route <em>\/api\/sign-up<\/em> zum Registrieren und <em>\/api\/login<\/em> zum Anmelden. Au\u00dferdem haben wir die Route <em>\/api\/secret-route<\/em>, diese soll man nur aufrufen k\u00f6nnen, wenn man angemeldet ist. Aktuell kann diese jeder Benutzer aufrufen. Dazu aber sp\u00e4ter mehr.<\/p>\n\n\n\n<p>In Zeile 10 binden wir au\u00dferdem unsere Datei f\u00fcr die Datenbank Verbindung ein.<\/p>\n\n\n\n<p>Wir binden noch die Datei <code>..\/middleware\/users.js<\/code> ein, in der befindet sich der Code um die Anfragen zu verifizieren. Das bedeutet, wir pr\u00fcfen dort, ob der Benutzer z.B. ein Passwort eingegeben hat und der Benutzername den Richtlinien entspricht. Diese Abfragen schalten wir sp\u00e4ter als Middleware in den Aufruf unserer Routen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"middleware\">4. Middleware zur Validierung erstellen<\/h2>\n\n\n\n<p>Die Logik f\u00fcr unser Node.js Login System verpacken wir in Middleware. Das ist quasi ein kleines Programm, was zwischen zwei Komponenten geschaltet ist. In diesem Fall haben wir zwischen unserem Request und der eigentlichen Registrierung eine Middleware, die die eingegebenen Daten validiert. F\u00fcr die Registrierung kann eine Validierung wie folgt aussehen:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ middleware\/users.js\n\nconst jwt = require(\"jsonwebtoken\");\n\nmodule.exports = {\n  validateRegister: (req, res, next) => {\n    \/\/ username min length 3\n    if (!req.body.username || req.body.username.length &lt; 3) {\n      return res.status(400).send({\n        message: 'Please enter a username with min. 3 chars',\n      });\n    }\n    \/\/ password min 6 chars\n    if (!req.body.password || req.body.password.length &lt; 6) {\n      return res.status(400).send({\n        message: 'Please enter a password with min. 6 chars',\n      });\n    }\n    \/\/ password (repeat) must match\n    if (\n      !req.body.password_repeat ||\n      req.body.password != req.body.password_repeat\n    ) {\n      return res.status(400).send({\n        message: 'Both passwords must match',\n      });\n    }\n    next();\n  }\n};\n<\/pre>\n\n\n\n<p>Beim Aufruf unserer <em>\/sign-up<\/em> Route soll unsere Middleware ausgef\u00fchrt werden. Dazu \u00e4ndern wie die markierte Zeile wie folgt ab:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"8\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/router.js\n\nconst express = require('express');\nconst router = express.Router();\n\nconst userMiddleware = require('..\/middleware\/users.js');\n\nrouter.post('sign-up', userMiddleware.validateRegister, (req, res, next) => {});\n\nrouter.post('login', (req, res, next) => {});\n\nmodule.exports = router;<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"5-logik-fuer-rest-api-erstellen\">5. Logik f\u00fcr Rest API erstellen<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"register\">5.1 Register Route<\/h3>\n\n\n\n<p>Um einen neuen Benutzer in die Datenbank aufzunehmen, m\u00fcssen wir \u00fcberpr\u00fcfen, ob der Benutzername noch nicht existiert. Ist der Benutzer vorhanden, wird eine Fehlermeldung ausgegeben. Ist der Benutzer noch nicht vorhanden, wird mittels unserem Modul <strong>bcryptjs<\/strong>, das eingegebene Passwort gehasht und dann alle Daten in die Datenbank eingetragen.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/router.js\n\nrouter.post('\/sign-up', userMiddleware.validateRegister, (req, res, next) => {\n  db.query(\n    'SELECT id FROM users WHERE LOWER(username) = LOWER(?)',\n    [req.body.username],\n    (err, result) => {\n      if (result &amp;&amp; result.length) {\n        \/\/ error\n        return res.status(409).send({\n          message: 'This username is already in use!',\n        });\n      } else {\n        \/\/ username not in use\n        bcrypt.hash(req.body.password, 10, (err, hash) => {\n          if (err) {\n            return res.status(500).send({\n              message: err,\n            });\n          } else {\n            db.query(\n              'INSERT INTO users (id, username, password, registered) VALUES (?, ?, ?, now());',\n              [uuid.v4(), req.body.username, hash],\n              (err, result) => {\n                if (err) {\n                  return res.status(400).send({\n                    message: err,\n                  });\n                }\n                return res.status(201).send({\n                  message: 'Registered!',\n                });\n              }\n            );\n          }\n        });\n      }\n    }\n  );\n});<\/pre>\n\n\n\n<p>Ist das Eintragen des Benutzers erfolgreich, wird der Statuscode 201 (&#8222;created&#8220;) zur\u00fcckgegeben und der Funktionsaufruf damit beendet.<\/p>\n\n\n\n<p class=\"info-notice info\">Schon mal von <em>Double Opt-In<\/em> geh\u00f6rt? Dabei werden Best\u00e4tigungsmails versendet, um eine Anmeldung zu verifizieren. In diesem Tutorial erf\u00e4hrst du, wie du <a href=\"https:\/\/webdeasy.de\/double-opt-in-node\/\">Double Opt-In in deine Node.js Anwendung<\/a> (aufbauend auf diesem Tutorial) einbauen kannst.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"login\">5.2 Login Route<\/h3>\n\n\n\n<p>Neben dem Registrierungsprozess haben wir in unserem Login System eine Login Route, um sich f\u00fcr bereits registrierte Benutzer anzumelden. Hier wird der passende Datenbankeintrag anhand des Benutzernamen gesucht. Danach wird das eingegebene mit dem verschl\u00fcsselten Passwort aus der Datenbank mit Hilfe von <code>jwt.compare()<\/code> \u00fcberpr\u00fcft. Ein kurzes SQL Query setzt in Zeile 45 das letzt Login Datum\/Zeit auf den aktuellen Wert.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"true\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/router.js\n\n[...]\nrouter.post('\/login', (req, res, next) => {\n  db.query(\n    `SELECT * FROM users WHERE username = ?;`,\n    [req.body.username],\n    (err, result) => {\n      if (err) {\n        return res.status(400).send({\n          message: err,\n        });\n      }\n      if (!result.length) {\n        return res.status(400).send({\n          message: 'Username or password incorrect!',\n        });\n      }\n\n      bcrypt.compare(\n        req.body.password,\n        result[0]['password'],\n        (bErr, bResult) => {\n          if (bErr) {\n            return res.status(400).send({\n              message: 'Username or password incorrect!',\n            });\n          }\n          if (bResult) {\n            \/\/ password match\n            const token = jwt.sign(\n              {\n                username: result[0].username,\n                userId: result[0].id,\n              },\n              'SECRETKEY',\n              { expiresIn: '7d' }\n            );\n            db.query(`UPDATE users SET last_login = now() WHERE id = ?;`, [\n              result[0].id,\n            ]);\n            return res.status(200).send({\n              message: 'Logged in!',\n              token,\n              user: result[0],\n            });\n          }\n          return res.status(400).send({\n            message: 'Username or password incorrect!',\n          });\n        }\n      );\n    }\n  );\n});<\/pre>\n\n\n\n<p>In Zeile 33 und 34 \u00fcbergeben wir Variablen, die wir im JWT Token &#8222;speichern&#8220; m\u00f6chten. Dadurch haben wir in den gesch\u00fctzten Routen Zugriff auf diese Variablen.<\/p>\n\n\n\n<p>In Zeile 36 musst du einen Key \u00fcbergeben, mit dem der JWT Token generiert wird, dieser ist sp\u00e4ter f\u00fcr die \u00dcberpr\u00fcfung wichtig. Hier kannst du einen beliebigen String eingeben.<\/p>\n\n\n\n<p>Au\u00dferdem kannst du in Zeile 37 festlegen, wie lange der Token g\u00fcltig sein soll. Werte wie &#8222;1h&#8220; oder &#8222;3m&#8220; sind hier g\u00fcltig. Die einzelnen Werte und Parameter kannst du auch <a aria-label=\"in der Dokumentation (\u00f6ffnet in neuem Tab)\" href=\"https:\/\/www.npmjs.com\/package\/jsonwebtoken\" target=\"_blank\" rel=\"noreferrer noopener\">in der Dokumentation<\/a> nachlesen.<\/p>\n\n\n\n<p>Falls das Passwort falsch ist oder der Benutzername nicht existiert wird eine Fehlermeldung ausgegeben. Diese Meldung ist absichtlich identisch, da ein potentieller Angreifer sonst Informationen \u00fcber das Existieren von einzelnen Benutzerprofilen bekommen kann.<\/p>\n\n\n\n<p>Bei erfolgreichem Login wird das Benutzerobjekt und der von JWT generierte Token zur\u00fcckgegeben. Dieser Token ist f\u00fcr alle Routen wichtig, in denen man eingeloggt sein soll. In Teil 2 dieses Node.js Login Tutorial erf\u00e4hrst du, wie du diesen bei jedem Request \u00fcbergeben kannst. Wenn du die Rest API mit Postman testest, kannst du den Token mit dem Key &#8222;Authorization&#8220; als Value nach folgender Syntax angeben: &#8222;Bearer <strong>KEY<\/strong>&#8222;.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"947\" height=\"169\" src=\"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/bearer.png\" alt=\"Postman Authorization Header\" class=\"wp-image-2089\" srcset=\"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/bearer.png 947w, https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/bearer-650x116.png 650w, https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/bearer-750x134.png 750w, https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/bearer-768x137.png 768w, https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/bearer-700x125.png 700w\" sizes=\"auto, (max-width: 947px) 100vw, 947px\" \/><figcaption class=\"wp-element-caption\">Postman Authorization Header<\/figcaption><\/figure>\n\n\n\n<p class=\"info-notice info\">Bei der Entwicklung einer Rest API kann es zu Fehlern kommen &#8211; das ist v\u00f6llig normal. Oft sind irgendwelche Randf\u00e4lle nicht bedacht. Wie du diese Testf\u00e4lle ausw\u00e4hlst und diese automatisiert testen kannst, habe ich dir hier zusammengefasst: <a href=\"https:\/\/webdeasy.de\/rest-api-testen\/\">Rest API richtig testen<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"protected-routes\">5.3 Routen mit Login<\/h3>\n\n\n\n<p>Die wichtigsten Routen sind nun fertig. Wir k\u00f6nnen neue Benutzer hinzuf\u00fcgen und uns mit bestehenden Accounts anmelden. Nun wollen wir noch Routen sch\u00fctzen. Das bedeutet, dass nur angemeldete Benutzer Zugriff darauf haben.<\/p>\n\n\n\n<p>Dazu legen wir in unserer <code>users.js<\/code> eine neue Middleware an. Hierbei wird der Token aus dem Header des Requests genommen und durch JWT verifiziert.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"13\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ middleware\/users.js\n\n  [...]\n  isLoggedIn: (req, res, next) => {\n    if (!req.headers.authorization) {\n      return res.status(400).send({\n        message: 'Your session is not valid!',\n      });\n    }\n    try {\n      const authHeader = req.headers.authorization;\n      const token = authHeader.split(' ')[1];\n      const decoded = jwt.verify(token, 'SECRETKEY');\n      req.userData = decoded;\n      next();\n    } catch (err) {\n      return res.status(400).send({\n        message: 'Your session is not valid!',\n      });\n    }\n  }\n  [...]<\/pre>\n\n\n\n<p>In der markierten Zeile musst du den gleichen Key angeben, mit dem du den JWT bereits generiert hast.<\/p>\n\n\n\n<p>Um nun eine Route zu sch\u00fctzen, bindest du diese Middleware einfach beim Aufruf der Route wie folgt ein:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"4\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/router.js\n\n[...]\nrouter.get('\/secret-route', userMiddleware.isLoggedIn, (req, res, next) => {\n  console.log(req.userData);\n  res.send('This is the secret content. Only logged in users can see that!');\n});\n[...]<\/pre>\n\n\n\n<p>In <code>req.userData<\/code> stehen die Daten die wir im JWT Key abgelegt haben (in diesem Fall <code>username<\/code> und <code>userId<\/code>). Damit k\u00f6nnen wir z.B. bei gesch\u00fctzten Routen benutzerdefinierte Werte aus der Datenbank anhand der <code>userId<\/code> auslesen.<\/p>\n\n\n\n<p class=\"has-primary-background-color has-background\"><a href=\"https:\/\/github.com\/webdeasy\/node-login-system\" target=\"_blank\" rel=\"noreferrer noopener\">Kompletten Code in Git Repository anschauen<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"6-node-js-login-system-deployen\">6. Node.js Login System deployen<\/h2>\n\n\n\n<p>Super, dein Node.js Login System mit Express, JWT und MySQL ist fertig. Jetzt kannst du dir ein schickes Frontend bauen und dein Backend anbinden.<\/p>\n\n\n\n<p>Wie du deine fertige App dann deployen &#8211; also live stellen kannst, habe ich dir in <a href=\"https:\/\/webdeasy.de\/nodejs-app-mit-plesk-deployen\/\">hier<\/a> beschrieben.<\/p>\n\n\n\n<p><a href=\"https:\/\/webdeasy.de\/login-system-mit-nodejs-vue-js-vuex-part-2-2\/\"><strong>\u27a1\ufe0f Hier geht\u2019s zum 2. Teil: Vue.js Login System mit Vuex &amp; Axios<\/strong><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In diesem Tutorial bauen wir ein Node.js Login System mit allen Basic Funktionen. Dazu nutzen wir Express, MySQL und JWT .<\/p>\n","protected":false},"author":1,"featured_media":8623,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[507,316],"tags":[],"class_list":["post-1935","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-node-js","category-sql","entry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Node.js Login System (mit Express, JWT &amp; MySQL)<\/title>\n<meta name=\"description\" content=\"Node.js Login System: Mit Express, JWT und MySQL erstellen wir ein komplettes NodeJS Login System auf Basis einer Rest API.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/webdeasy.de\/nodejs-login-system\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Node.js Login System (mit Express, JWT &amp; MySQL)\" \/>\n<meta property=\"og:description\" content=\"Node.js Login System: Mit Express, JWT und MySQL erstellen wir ein komplettes NodeJS Login System auf Basis einer Rest API.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/webdeasy.de\/nodejs-login-system\/\" \/>\n<meta property=\"og:site_name\" content=\"webdeasy.de\" \/>\n<meta property=\"article:published_time\" content=\"2019-10-14T22:00:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-06-09T13:31:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/10\/node-login-system.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1400\" \/>\n\t<meta property=\"og:image:height\" content=\"600\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Lorenz\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webdeasy\" \/>\n<meta name=\"twitter:site\" content=\"@webdeasy\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lorenz\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/\"},\"author\":{\"name\":\"Lorenz\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/#\\\/schema\\\/person\\\/42d507baee923988d706529843341fd7\"},\"headline\":\"Node.js Login System (mit Express, JWT &amp; MySQL)\",\"datePublished\":\"2019-10-14T22:00:27+00:00\",\"dateModified\":\"2024-06-09T13:31:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/\"},\"wordCount\":1583,\"commentCount\":25,\"publisher\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/#\\\/schema\\\/person\\\/42d507baee923988d706529843341fd7\"},\"image\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/10\\\/node-login-system.jpg\",\"articleSection\":[\"Node.js\",\"SQL\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/\",\"url\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/\",\"name\":\"Node.js Login System (mit Express, JWT &amp; MySQL)\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/10\\\/node-login-system.jpg\",\"datePublished\":\"2019-10-14T22:00:27+00:00\",\"dateModified\":\"2024-06-09T13:31:36+00:00\",\"description\":\"Node.js Login System: Mit Express, JWT und MySQL erstellen wir ein komplettes NodeJS Login System auf Basis einer Rest API.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#primaryimage\",\"url\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/10\\\/node-login-system.jpg\",\"contentUrl\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/10\\\/node-login-system.jpg\",\"width\":1400,\"height\":600},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/nodejs-login-system\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/webdeasy.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript\",\"item\":\"https:\\\/\\\/webdeasy.de\\\/category\\\/javascript\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Node.js\",\"item\":\"https:\\\/\\\/webdeasy.de\\\/category\\\/javascript\\\/node-js\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Node.js Login System (mit Express, JWT &amp; MySQL)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/#website\",\"url\":\"https:\\\/\\\/webdeasy.de\\\/\",\"name\":\"webdeasy.de\",\"description\":\"Backend-Development, DevOps &amp; Co.\",\"publisher\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/#\\\/schema\\\/person\\\/42d507baee923988d706529843341fd7\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/webdeasy.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/webdeasy.de\\\/#\\\/schema\\\/person\\\/42d507baee923988d706529843341fd7\",\"name\":\"Lorenz\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/cropped-webdeasy-logo-3.png\",\"url\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/cropped-webdeasy-logo-3.png\",\"contentUrl\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/cropped-webdeasy-logo-3.png\",\"width\":190,\"height\":190,\"caption\":\"Lorenz\"},\"logo\":{\"@id\":\"https:\\\/\\\/webdeasy.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/cropped-webdeasy-logo-3.png\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/webdeasy\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Node.js Login System (mit Express, JWT &amp; MySQL)","description":"Node.js Login System: Mit Express, JWT und MySQL erstellen wir ein komplettes NodeJS Login System auf Basis einer Rest API.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/webdeasy.de\/nodejs-login-system\/","og_locale":"de_DE","og_type":"article","og_title":"Node.js Login System (mit Express, JWT &amp; MySQL)","og_description":"Node.js Login System: Mit Express, JWT und MySQL erstellen wir ein komplettes NodeJS Login System auf Basis einer Rest API.","og_url":"https:\/\/webdeasy.de\/nodejs-login-system\/","og_site_name":"webdeasy.de","article_published_time":"2019-10-14T22:00:27+00:00","article_modified_time":"2024-06-09T13:31:36+00:00","og_image":[{"width":1400,"height":600,"url":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/10\/node-login-system.jpg","type":"image\/jpeg"}],"author":"Lorenz","twitter_card":"summary_large_image","twitter_creator":"@webdeasy","twitter_site":"@webdeasy","twitter_misc":{"Verfasst von":"Lorenz","Gesch\u00e4tzte Lesezeit":"9\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#article","isPartOf":{"@id":"https:\/\/webdeasy.de\/nodejs-login-system\/"},"author":{"name":"Lorenz","@id":"https:\/\/webdeasy.de\/#\/schema\/person\/42d507baee923988d706529843341fd7"},"headline":"Node.js Login System (mit Express, JWT &amp; MySQL)","datePublished":"2019-10-14T22:00:27+00:00","dateModified":"2024-06-09T13:31:36+00:00","mainEntityOfPage":{"@id":"https:\/\/webdeasy.de\/nodejs-login-system\/"},"wordCount":1583,"commentCount":25,"publisher":{"@id":"https:\/\/webdeasy.de\/#\/schema\/person\/42d507baee923988d706529843341fd7"},"image":{"@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#primaryimage"},"thumbnailUrl":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/10\/node-login-system.jpg","articleSection":["Node.js","SQL"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/webdeasy.de\/nodejs-login-system\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/webdeasy.de\/nodejs-login-system\/","url":"https:\/\/webdeasy.de\/nodejs-login-system\/","name":"Node.js Login System (mit Express, JWT &amp; MySQL)","isPartOf":{"@id":"https:\/\/webdeasy.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#primaryimage"},"image":{"@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#primaryimage"},"thumbnailUrl":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/10\/node-login-system.jpg","datePublished":"2019-10-14T22:00:27+00:00","dateModified":"2024-06-09T13:31:36+00:00","description":"Node.js Login System: Mit Express, JWT und MySQL erstellen wir ein komplettes NodeJS Login System auf Basis einer Rest API.","breadcrumb":{"@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/webdeasy.de\/nodejs-login-system\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#primaryimage","url":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/10\/node-login-system.jpg","contentUrl":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/10\/node-login-system.jpg","width":1400,"height":600},{"@type":"BreadcrumbList","@id":"https:\/\/webdeasy.de\/nodejs-login-system\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/webdeasy.de\/"},{"@type":"ListItem","position":2,"name":"JavaScript","item":"https:\/\/webdeasy.de\/category\/javascript\/"},{"@type":"ListItem","position":3,"name":"Node.js","item":"https:\/\/webdeasy.de\/category\/javascript\/node-js\/"},{"@type":"ListItem","position":4,"name":"Node.js Login System (mit Express, JWT &amp; MySQL)"}]},{"@type":"WebSite","@id":"https:\/\/webdeasy.de\/#website","url":"https:\/\/webdeasy.de\/","name":"webdeasy.de","description":"Backend-Development, DevOps &amp; Co.","publisher":{"@id":"https:\/\/webdeasy.de\/#\/schema\/person\/42d507baee923988d706529843341fd7"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/webdeasy.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":["Person","Organization"],"@id":"https:\/\/webdeasy.de\/#\/schema\/person\/42d507baee923988d706529843341fd7","name":"Lorenz","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/cropped-webdeasy-logo-3.png","url":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/cropped-webdeasy-logo-3.png","contentUrl":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/cropped-webdeasy-logo-3.png","width":190,"height":190,"caption":"Lorenz"},"logo":{"@id":"https:\/\/webdeasy.de\/wp-content\/uploads\/2019\/09\/cropped-webdeasy-logo-3.png"},"sameAs":["https:\/\/x.com\/webdeasy"]}]}},"_links":{"self":[{"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/posts\/1935","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/comments?post=1935"}],"version-history":[{"count":3,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/posts\/1935\/revisions"}],"predecessor-version":[{"id":9500,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/posts\/1935\/revisions\/9500"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/media\/8623"}],"wp:attachment":[{"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/media?parent=1935"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/categories?post=1935"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webdeasy.de\/wp-json\/wp\/v2\/tags?post=1935"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}