Node.js Login System mit Express, JWT & MySQL (Rest API)

Node.js Login System mit Express, JWT & MySQL (Rest API) Thumbnail
Veröffentlicht am 15. Oktober 2019Zuletzt aktualisiert am 9. Mai 2021

In diesem Beitrag erfährst Du, wie Du mit Node.js, Express, JWT (JSON Web Tokens) und MySQL eine eigene Rest API für die Authentifizierung von Benutzern – also ein komplettes Node.js Login System – erstellen kannst.

Anzeige

Dieser Beitrag ist der erste Teil der zweiteiligen Serie zur Erstellung eines kompletten Login Systems mit Node.js und Vue.js. Dazu nutzen wir Node.js als Backend und Vue.js als Frontend.

Das Tutorial ist in zwei Beiträge aufgeteilt, damit Du nicht an ein Vue.js Frontend gebunden bist, sondern die Rest API, die wir in diesem Beitrag entwickeln genau so gut auf andere Frontends, wie Angular oder React anwenden kannst.

Hier geht’s zu Teil 2: Vue.js Login System mit Vuex & Axios

Unser Ziel: Node.js Login – Rest API mit Express, JWT und MySQL

Wir erstellen eine Node.js Anwendung, die auf unserem lokalen Server läuft. Dazu haben wir eine MySQL Datenbank, in der unsere Benutzerdaten gespeichert sind. Zur Authentifizierung müssen wir diese Daten dann abfragen und können mit Hilfe der JWT (JSON Web Token) Erweiterung eine Session (Sitzung) für den Benutzer eröffnen.

Am Ende hast Du eine lauffähige Anwendung, die mit Hilfe dieser Anleitung auf deinem eigenen Server deployen (live stellen) kannst. Aber nun wollen wir endlich starten! 🙂

Anzeige

Hier gibt es das Tutorial auch in Videoform:

1. Was ist eine Rest API?

Eine Rest API stellt die Schnittstelle zwischen Server und Client dar. Über normale HTTP Anfragen erreichen wir den Server und können programmierte Funktionen ausführen, wie das Authentifizieren eines Benutzers mit zugehörigem Passwort.

Da dieses Tutorial nicht für absolute Einsteiger geeignet ist, gehe ich davon aus, dass Du bereits mit Node.js etwas vertraut bist, weshalb wir die Installation überspringen und direkt zum spannenden Teil kommen. Solltest Du mit Node.js noch nicht vertraut sein, kannst Du dir dieses Node.js Anfänger Tutorial anschauen. Danach hast Du alle Grundlagen drauf und kannst Dich an Dein Node.js Login System wagen.

2. Abhängigkeiten installieren

Unsere Node.js App ist also bereit für die Installation der Abhängigkeiten. Wir benötigen folgende Module:

PackageBeschreibung
expressDamit erstellen wir unseren eigenen Webserver für unsere Rest API
body-parserEinfachere Handhabung von Middleware für Requests
mysqlZum Lesen/Schreiben in unsere Datenbank
uuidZum Erstellen von IDs für spätere Benutzer
bcryptjs (Achtung: nicht bcrypt)Zum Ver-/Entschlüsseln der Passwörter
jsonwebtokenZur Handhabung der Nutzer-Sessions
corsDamit wir die Rest API von unserer Website aufrufen können.

Diese Module installieren wir über folgenden CLI Befehl:

npm install bcryptjs body-parser express jsonwebtoken mysql uuid cors

3. MySQL-Datenbank einrichten

Für die Datenbank nutze ich XAMPP, damit ich mir eine eigene Datenbank lokal hosten kann. Natürlich kannst Du auch jede andere (Remote-) Datenbank verwenden.

Für unser Login System benötigen wir nur eine Tabelle nach folgendem Schema:

Anzeige
ER-Modell der "users" Tabelle
ER-Modell der „users“ Tabelle

In der Datenbank sieht unsere Tabelle dann folgendermaßen aus:

phpMyAdmin Ansicht der "users" Tabelle
phpMyAdmin Ansicht der „users“ Tabelle

Damit wir auch über unsere Node.js Anwendung auf diese Verbindung zugreifen können, erstellen wir eine eigene Klasse Datei, die wir später in unserem Router einbinden.

// lib/db.js

const mysql = require('mysql');

const connection = mysql.createConnection({
	host: 'localhost',
	user: 'node-jwt',
	database: 'node-jwt',
	password: '********'
});

connection.connect();
module.exports = connection;

4. Express Router aufsetzen und Routen erstellen

Unsere Einstiegsdatei ist die index.js und beinhaltet das Starten unsere Webservers und die Einbindung der Routen, die wir in der Datei routes/router.js definieren.

// index.js

const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');

// set up port
const PORT = process.env.PORT || 3000;

app.use(bodyParser.json());
app.use(cors());

// add routes
const router = require('./routes/router.js');
app.use('/api', router);

// run server
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

In der router.js definieren wir unsere Routen und verpacken danach die Logik darin. Grund, wieso wir hier eine extra Datei benutzen ist die Übersichtlichkeit. Wenn Deine Anwendung irgendwann 20 oder noch mehr Routen hat, gibt es ein großes Chaos in der index.js. Deshalb lagern wir unsere Routen aus.

// routes/router.js

const express = require('express');
const router = express.Router();

const bcrypt = require('bcryptjs');
const uuid = require('uuid');
const jwt = require('jsonwebtoken');

const db = require('../lib/db.js');
const userMiddleware = require('../middleware/users.js');

router.post('/sign-up', (req, res, next) => {});

router.post('/login', (req, res, next) => {});

router.get('/secret-route', (req, res, next) => {
	res.send('This is the secret content. Only logged in users can see that!');
});

module.exports = router;

Hier registrieren wir die Route /api/sign-up zum Registrieren und /api/login zum Anmelden. Außerdem haben wir die Route /api/secret-route, diese soll man nur aufrufen können, wenn man angemeldet ist. Aktuell kann diese jeder Benutzer aufrufen. Dazu aber später mehr.

In Zeile 10 binden wir außerdem unsere Datei für die Datenbank Verbindung ein.

Wir binden noch die Datei ../middleware/users.js ein, in der befindet sich der Code um die Anfragen zu verifizieren. Das bedeutet, wir prüfen dort, ob der Benutzer z.B. ein Passwort eingegeben hat und der Benutzername den Richtlinien entspricht. Diese Abfragen schalten wir später als Middleware in den Aufruf unserer Routen.

Anzeige

5. Middleware erstellen (Validierung)

Eine Middleware 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ür die Registrierung kann eine Validierung wie folgt aussehen:

// middleware/users.js

const jwt = require("jsonwebtoken");

module.exports = {
	validateRegister: (req, res, next) => {
		// username min length 3
		if (!req.body.username || req.body.username.length < 3) {
			return res.status(400).send({
				msg: 'Please enter a username with min. 3 chars'
			});
		}

		// password min 6 chars
		if (!req.body.password || req.body.password.length < 6) {
			return res.status(400).send({
				msg: 'Please enter a password with min. 6 chars'
			});
		}

		// password (repeat) does not match
		if (
			!req.body.password_repeat ||
			req.body.password != req.body.password_repeat
		) {
			return res.status(400).send({
				msg: 'Both passwords must match'
			});
		}

		next();
	}
};

Beim Aufruf unserer /sign-up Route soll unsere Middleware ausgeführt werden. Dazu ändern wie die markierte Zeile wie folgt ab:

// routes/router.js

const express = require('express');
const router = express.Router();

const userMiddleware = require('../middleware/users.js');

router.post('sign-up', userMiddleware.validateRegister, (req, res, next) => {});

router.post('login', (req, res, next) => {});

module.exports = router;

6. Register (/sign-up) Route umsetzen (mit JWT)

Um einen neuen Benutzer in die Datenbank aufzunehmen, müssen wir überprüfen, ob der Benutzername noch nicht existiert. Ist der Benutzer vorhanden, wird eine Fehlermeldung ausgegeben. Ist der Benutzer noch nicht vorhanden, wird mittels unserem Modul bcrypt, das eingegebene Passwort gehasht (verschlüsselt) und dann alle Daten in die Datenbank eingetragen.

// routes/router.js

router.post('/sign-up', userMiddleware.validateRegister, (req, res, next) => {
  db.query(
    `SELECT * FROM users WHERE LOWER(username) = LOWER(${db.escape(
			req.body.username
		)});`,
    (err, result) => {
      if (result.length) {
        return res.status(409).send({
          msg: 'This username is already in use!'
        });
      } else {
        // username is available
        bcrypt.hash(req.body.password, 10, (err, hash) => {
          if (err) {
            return res.status(500).send({
              msg: err
            });
          } else {
            // has hashed pw => add to database
            db.query(
              `INSERT INTO users (id, username, password, registered) VALUES ('${uuid.v4()}', ${db.escape(
								req.body.username
							)}, ${db.escape(hash)}, now())`,
              (err, result) => {
                if (err) {
                  throw err;
                  return res.status(400).send({
                    msg: err
                  });
                }
                return res.status(201).send({
                  msg: 'Registered!'
                });
              }
            );
          }
        });
      }
    }
  );
});

Wichtig ist die Funktion db.escape(), beispielsweise in Zeile 25. Hiermit werden übergebene Parameter maskiert, um eine SQL Injection zu vermeiden. Ist das Eintragen des Benutzers erfolgreich, wird der Statuscode 201 („created“) zurückgegeben und der Funktionsaufruf damit beendet.

Schon mal von Double Opt-In gehört? Dabei werden Bestätigungsmails versendet, um eine Anmeldung zu verifizieren. In diesem Tutorial erfährst Du, wie Du Double Opt-In in Deine Node.js Anwendung (aufbauend auf diesem Tutorial) einbauen kannst.

7. Login (/login) Route umsetzen (mit JWT)

Neben dem Registrierungsprozess haben wir eine Login Route, um sich für bereits registrierte Benutzer anzumelden. Hier wird der passende Datenbankeintrag anhand des Benutzernamen gesucht. Danach wird das eingegebene mit dem verschlüsselten Passwort aus der Datenbank mit Hilfe von jwt.compare() überprüft. Ein kurzes SQL Query setzt in Zeile 44 das letzt Login Datum/Zeit auf den aktuellen Wert.

// routes/router.js

router.post('/login', (req, res, next) => {
  db.query(
    `SELECT * FROM users WHERE username = ${db.escape(req.body.username)};`,
    (err, result) => {
      // user does not exists
      if (err) {
        throw err;
        return res.status(400).send({
          msg: err
        });
      }

      if (!result.length) {
        return res.status(401).send({
          msg: 'Username or password is incorrect!'
        });
      }

      // check password
      bcrypt.compare(
        req.body.password,
        result[0]['password'],
        (bErr, bResult) => {
          // wrong password
          if (bErr) {
            throw bErr;
            return res.status(401).send({
              msg: 'Username or password is incorrect!'
            });
          }

          if (bResult) {
            const token = jwt.sign({
                username: result[0].username,
                userId: result[0].id
              },
              'SECRETKEY', {
                expiresIn: '7d'
              }
            );

            db.query(
              `UPDATE users SET last_login = now() WHERE id = '${result[0].id}'`
            );
            return res.status(200).send({
              msg: 'Logged in!',
              token,
              user: result[0]
            });
          }
          return res.status(401).send({
            msg: 'Username or password is incorrect!'
          });
        }
      );
    }
  );
});

In Zeile 36 und 37 übergeben wir Variablen, die wir im JWT Token „speichern“ möchten. Dadurch haben wir in den geschützten Routen Zugriff auf diese Variablen.

Anzeige

In Zeile 39 musst Du einen Key übergeben, mit dem der JWT Token generiert wird, dieser ist später für die Überprüfung wichtig. Hier kannst Du einen beliebigen String eingeben.

Außerdem kannst Du in Zeile 40 festlegen, wie lange der Token gültig sein soll. Werte wie „1h“ oder „3m“ sind hier gültig. Die einzelnen Werte und Parameter kannst Du auch in der Dokumentation nachlesen.

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 über das Existieren von einzelnen Benutzerprofilen bekommen kann.

Bei erfolgreichem Login wird das Benutzerobjekt und der von JWT generierte Token zurückgegeben. Dieser Token ist für alle Routen wichtig, in denen man eingeloggt sein soll. Im Teil 2 (Vue.js Frontend) erfährst Du, wie Du diesen bei jedem Request übergeben kannst. Wenn Du die Rest API mit Postman testest, kannst Du den Token mit dem Key „Authorization“ als Value nach folgender Syntax angeben: „Bearer KEY“.

Postman Authorization Header
Postman Authorization Header

8. Routen mit Login schützen

Die wichtigsten Routen sind nun fertig. Wir können neue Benutzer hinzufügen und uns mit bestehenden Accounts anmelden. Nun wollen wir noch Routen schützen. Das bedeutet, dass nur angemeldete Benutzer Zugriff darauf haben.

Dazu legen wir in unserer users.js eine neue Middleware an. Hierbei wird der Token aus dem Header des Requests genommen und durch JWT verifiziert.

// middleware/users.js

isLoggedIn: (req, res, next) => {
  try {
    const token = req.headers.authorization.split(' ')[1];
    const decoded = jwt.verify(
      token,
      'SECRETKEY'
    );
    req.userData = decoded;
    next();
  } catch (err) {
    return res.status(401).send({
      msg: 'Your session is not valid!'
    });
  }
}

In der markierten Zeile musst Du den gleichen Key angeben, mit dem Du den JWT bereits generiert hast.

Anzeige

Um nun eine Route zu schützen, bindest Du diese Middleware einfach beim Aufruf der Route wie folgt ein:

// routes/router.js

router.get('/secret-route', userMiddleware.isLoggedIn, (req, res, next) => {
  console.log(req.userData);
  res.send('This is the secret content. Only logged in users can see that!');
});

In req.userData stehen die Daten die wir im JWT Key abgelegt haben (in diesem Fall username und userId). Damit können wir z.B. bei geschützten Routen benutzerdefinierte Werte aus der Datenbank anhand der userId auslesen.

Bei der Entwicklung einer Rest API kann es zu Fehlern kommen – das ist völlig normal. Oft sind irgendwelche Randfälle nicht bedacht. Wie Du diese Testfälle auswählst und diese automatisiert testen kannst, habe ich Dir hier zusammengefasst:

Rest API mit Postman testen

9. Fazit

➡️ Hier geht’s zum 2. Teil: Vue.js Login System mit Vuex & Axios

That’s it! Im ersten Teil haben wir nun eine komplette Rest API für die Validierung und das Session Handling für unsere Anwendung geschrieben. Dieses Node.js Login System kannst Du für Dein Frontend (egal, ob Angular, React oder Vue) verwenden. Danke für’s Lesen! 🙂

Ähnliche Beiträge
💬 Beteilige dich an der Unterhaltung

15 Kommentare

  1. Edi sagt:

    Hi,die grössten Teil habe ich mitmachen können. Dein Authetifizierung habe ich meine Todo-app eingebaut. Neue user registrieren funktioniert, auch bei falsche Eingaben zeigt es richtige Fehler Meldungen. Login funktioniert auch ABER wenn ich die falsche Daten bei Login eingebe, werden keine Meldungen angezeigt. Es landet immer in catch-teil!! Wo liege ich falsch?async login() { try { const credentials = { username: this.username, password: this.password }; const response = await AuthService.login(credentials); this.msg = response.message; console.log(„Message“ + response.msg + response.user) const token = response.token; const user = response.user; this.$store.dispatch(‚login‘, { token, user }); this.$router.push(‚/‘); } catch (error) { console.log(„something is wrong. Message: “ + this.msg) this.msg = error.response.data.msg; }

    1. LH sagt:

      Lass dir mal vor await AuthService.login(credentials) das credentials ausgeben. Eventuell wurden dort nicht alle Werte korrekt gesetzt.  Vielleicht hast du auch in der AuthService.js die URL falsch gesetzt. Lass dir Schritt für Schritt Sachen ausgeben, dann wirst du den Fehler finden.

      Meld dich falls Du nicht weiter kommst

      Viele Grüße
      Lorenz

  2. Alexander Wottschel sagt:

    Danke für die schöne Anleitung. Zwar für einen Laien immer noch ziemlich wild, was es alles braucht, um eine Node.js- Anwendung auf dem Server zu laufen zu bringen, aber die meisten anderen Anleitungen fand ich noch komplizierter.
    Nun habe ich das ausprobiert und kriege am Ende einen Fehler, sobald ich die Routen einbinden will.

    in der index.js sind ja folgende Zeilen:
    const router = require(‚./routes/router.js‘);
    app.use(‚/api‘, router);

    an der Stelle überrascht mich der Pfad „/api“. Dieser wurde bisher doch nirgends erwähnt. Wieso taucht dieser hier auf einmal auf? Was ist da drin? wenn ich das richtig interpretiere, muss SignIn und Login dort rein? Ich glaube bei mir passt mit dem Pfaden etwas nicht. Cool wäre ein Screenshot, wie das in etwa alles aussieht bis hierher.

    Hier mein aktueller Fehler und nun versuche ich mich etwas einzulesen, um was zu verstehen.

    Server running on port 3000
    events.js:292
    throw er; // Unhandled ‚error‘ event
    ^

    Error: getaddrinfo ENOTFOUND localhost
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26)
    ——————–
    at Protocol._enqueue (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/protocol/Protocol.js:144:48)
    at Protocol.handshake (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/protocol/Protocol.js:51:23)
    at Connection.connect (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/Connection.js:116:18)
    at Object. (/Users/codeagent/_workspace/root-tree/lib/db.js:8:12)
    at Module._compile (internal/modules/cjs/loader.js:1063:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
    at Module.load (internal/modules/cjs/loader.js:928:32)
    at Function.Module._load (internal/modules/cjs/loader.js:769:14)
    at Module.require (internal/modules/cjs/loader.js:952:19)
    at require (internal/modules/cjs/helpers.js:88:18)
    Emitted ‚error‘ event on Connection instance at:
    at Connection._handleProtocolError (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/Connection.js:423:8)
    at Protocol.emit (events.js:315:20)
    at Protocol._delegateError (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/protocol/Protocol.js:398:10)
    at Handshake. (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/protocol/Protocol.js:153:12)
    at Handshake.emit (events.js:315:20)
    at Handshake.Sequence.end (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/protocol/sequences/Sequence.js:78:12)
    at Protocol.handleNetworkError (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/protocol/Protocol.js:369:14)
    at Connection._handleNetworkError (/Users/codeagent/_workspace/root-tree/node_modules/mysql/lib/Connection.js:418:18)
    at Socket.emit (events.js:315:20)
    at emitErrorNT (internal/streams/destroy.js:106:8) {
    errno: -3008,
    code: ‚ENOTFOUND‘,
    syscall: ‚getaddrinfo‘,
    hostname: ‚localhost‘,
    fatal: true
    }

    1. LH sagt:

      Hi Alexander!

      Der Fehler scheint von der Datenbank Verbindung (mysql) zu kommen. Schau mal, ob der Datenbank Part richtig ist und vor allem: ob die Zugangsdaten stimmen. Kommentiere doch bis die Frage mit den Routen geklärt ist die Zeile 10 (const db = require('../lib/db.js');) noch mal aus, damit der Fehler da nicht reinfunkt.

      Die Routen die wir erstellen lauten: http://localhost:3000/api/login, http://localhost:3000/api/sign-up und http://localhost:3000/api/secret-rout (bzw. statt localhost die Adresse des Servers). Mit dem Aufruf
      const router = require(‚./routes/router.js‘);
      app.use(‚/api‘, router);
      lagern wir den Code einfach nur in die router.js aus. Daraus ergibt sich dann eben auch der Pfad mit /api davor. Das ist aber einfach nur Geschmacksache. Wenn Deine Routen http://localhost:3000/login so aussehen sollen, ohne /api kannst Du einfach app.use(‚/‘, router); schreiben.

      Hoffe das Ganze ist jetzt etwas verständlicher 🙂

      Viele Grüße
      LH

      1. Alexander Wottschel sagt:

        oh man, den Fehler hätte man auch googeln können. Danke, klappt nun 🙂

        1. LH sagt:

          Kein Problem, Hauptsache es geht jetzt 😉

  3. Jonas Mahdalicek sagt:

    Hi,

    habe das Tutorial nachgemacht, leider funktioniert es bei mir nicht. Es kommt folgender fail log:

    0 info it worked if it ends with ok
    1 verbose cli [
    1 verbose cli 'C:\\Program Files\\nodejs\\node.exe',
    1 verbose cli 'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
    1 verbose cli 'start'
    1 verbose cli ]
    2 info using npm@6.14.11
    3 info using node@v14.16.0
    4 verbose run-script [ 'prestart', 'start', 'poststart' ]
    5 info lifecycle server-backend@0.0.0~prestart: server-backend@0.0.0
    6 info lifecycle server-backend@0.0.0~start: server-backend@0.0.0
    7 verbose lifecycle server-backend@0.0.0~start: unsafe-perm in lifecycle true
    8 verbose lifecycle server-backend@0.0.0~start: PATH: C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\node-gyp-bin;C:\Users\herbe\WebstormProjects\Server_Backend\node_modules\.bin;C:\Users\herbe\WebstormProjects\Server_Backend\node_modules\.bin;C:\ProgramData\Oracle\Java\javapath;C:\Python27\;C:\Python27\Scripts;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Java\jdk1.8.0_201\bin;C:\Program Files\apache-maven-3.6.0-bin\apache-maven-3.6.0\bin;C:\Program Files\PuTTY\;C:\ProgramData\chocolatey\bin;C:\Program Files\Git\cmd;C:\Program Files\nodejs\;C:\Users\herbe\AppData\Local\Microsoft\WindowsApps;C:\Users\herbe\AppData\Local\Programs\Microsoft VS Code\bin;C:\Program Files (x86)\Nmap;C:\Users\herbe\AppData\Local\gitkraken\bin;C:\Users\herbe\AppData\Roaming\npm
    9 verbose lifecycle server-backend@0.0.0~start: CWD: C:\Users\herbe\WebstormProjects\Server_Backend
    10 silly lifecycle server-backend@0.0.0~start: Args: [ '/d /s /c', 'node ./bin/www' ]
    11 silly lifecycle server-backend@0.0.0~start: Returned: code: 1 signal: null
    12 info lifecycle server-backend@0.0.0~start: Failed to exec start script
    13 verbose stack Error: server-backend@0.0.0 start: `node ./bin/www`
    13 verbose stack Exit status 1
    13 verbose stack at EventEmitter. (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\index.js:332:16)
    13 verbose stack at EventEmitter.emit (events.js:315:20)
    13 verbose stack at ChildProcess. (C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\lib\spawn.js:55:14)
    13 verbose stack at ChildProcess.emit (events.js:315:20)
    13 verbose stack at maybeClose (internal/child_process.js:1048:16)
    13 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:288:5)
    14 verbose pkgid server-backend@0.0.0
    15 verbose cwd C:\Users\herbe\WebstormProjects\Server_Backend
    16 verbose Windows_NT 10.0.18363
    17 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "start"
    18 verbose node v14.16.0
    19 verbose npm v6.14.11
    20 error code ELIFECYCLE
    21 error errno 1
    22 error server-backend@0.0.0 start: `node ./bin/www`
    22 error Exit status 1
    23 error Failed at the server-backend@0.0.0 start script.
    23 error This is probably not a problem with npm. There is likely additional logging output above.
    24 verbose exit [ 1, true ]

    Hätte da jemand eine Ahnung was da nicht funktioniert?
    Danke im Voraus.
    Lg

    1. LH sagt:

      Hi, wann tritt das Problem auf?

  4. Markus sagt:

    Hi,

    klasse Tutorial. Für mich als Einsteiger in Node.js gut und nachvollziehbar beschrieben.
    Eine Frage habe ich dennoch, in der users.js gab es bei isLoggedIn einen Fehler, weil jwt nicht deklariert war.
    Nachdem ich das nachgeholt habe, funktionierte auch der Aufruf einer URL als eingeloggter User.
    Fehlt das im Tutorial oder hab ich was falsch gemacht?

    Liebe Grüße,
    Markus

    1. LH sagt:

      Hallo, danke! Da hat es sich tatsächlich um einen Fehler gehandelt, hab es ergänzt. Danke für den Hinweis 🙂

      Viele Grüße
      Lorenz

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.