Komplettes Login System mit Node.js & Vue.js | Vuex | Part [2/2]

Komplettes Login System mit Node.js & Vue.js | Vuex | Part [2/2]

In diesem Beitrag erfährst Du, wie Du mit Vue.js, Vuex und Axios das Frontend für ein komplettes Login System programmieren kannst.

Dieser Beitrag ist der zweite Teil der zweiteiligen Serie Komplettes Login System mit Node.js & Vue.js. Wir kümmern uns hier um die Umsetzung eines kompletten Login Systems mit Node.js als Backend und Vue.js als Frontend. Das Tutorial ist in zwei Beiträge aufgeteilt, damit Du nicht an eine Node.js RestAPI gebunden bist, sondern das Vue.js Frontend auch mit einem anderen System Deiner Wahl, wie PHP oder Python nutzen kannst.

➡️ Teil 1: Komplettes Login System mit Node.js & Vue.js | RestAPI & JWT

Unser Ziel für Teil 2: Vue.js Frontend mit Vuex und Axios

Wir erstellen ein Vue.js Frontend, wo wir eine Session für den Benutzer erstellen, diese speichern und immer wieder darauf zugreifen können, um zu prüfen, ob ein Benutzer angemeldet ist und eine gültige Session hat. Dazu verwenden wir die Vue CLI, Axios, Vuex und das Modul vuex-persistedstate zum temporären Speichern der Session.

Am Ende hast Du eine Webanwendung, auf der sich Benutzer registrieren und einloggen können. Zusätzlich sollen manche Seiten nur erreichbar sein, wenn der Benutzer eine gültige Session hat, also angemeldet ist. Aber nun wollen wir endlich starten! 🙂

Tasse mit Aufschrift

1. Funktionsweise von Vuex

Vuex ist quasi ein „Store“, in dem verschiedene Stati gespeichert werden. Werden diese Daten angepasst, updated sich Dein Vue Component automatisch. Das nutzen wir dazu, um den Login Status des Users zu speichern um Zugriff auf verschiedene Routen zu bekommen und angepasste Texte, etc. anzeigen zu lassen.

Außerdem nutzen wir vuex-persistedstate, um die Daten auch nach dem Neuladen der Seite noch zu erhalten. Dazu aber in Schritt 3 mehr.

2. Vue App initialisieren

Zu Beginn müssen wir die Vue App über die Vue CLI initialisieren. Das machen wir mit folgenden Befehl:

vue create client

Dabei müssen wir verschiedene Komponenten und Module anwählen, die standardmäßig installiert sein sollen. Hier ist es sinnvoll ein eigenes Preset zu erstellen (hier „lh-standard“) und für zukünftige Projekte zu nutzen. Du solltest hier also „Manually select features“ auswählen. Für dieses Tutorial benötigen wir unbedingt die Module vue-router und vuex. Alles Weitere ist optional.

Vue Create

Ist der Prozess abgeschlossen, erhälst Du einen Ordner mit dieser (oder ähnlicher) Struktur.

Vue Ordnerstruktur

3. Abhängigkeiten installieren

Im nächsten Schritt müssen wir zusätzliche Packages installieren. Darunter axios, um HTTP Anfragen zu senden und vuex-persistedstate, um die Daten aus Vuex auch nach dem Neuladen der Seite zu erhalten.

npm install axios vuex-persistedstate

4. Routen erstellen

Nun legen wir drei Routen an:

  • …/ => Diese Route soll nur für angemeldete Benutzer erreichbar sein
  • …/sign-up => Registrierungs Seite
  • …/login => Login Seite

Dazu passen wir die Standard Router Datei an, und weißen den einzelnen Routen jeweils einen eigenen Vuex View zu.

// src/router.js

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import SignUp from "./views/SignUp.vue";
import Login from "./views/Login.vue";

Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "home",
      component: Home
    },
    {
      path: "/sign-up",
      name: "sign-up",
      component: SignUp
    },
    {
      path: "/login",
      name: "login",
      component: Login
    },
  ]
});

5. Vuex einrichten

Im nächsten Schritt müssen wir Vuex einrichten. Dazu integrieren wir das Plugin vuex-persistedstate (Zeile 6 und 21). Das hilft uns, Daten auch nach dem Neuladen der Seite noch zu erhalten.

Um die Daten zu „speichern“ legen wir nun die Stati token und user an. Außerdem erstellen wir Aktionen für Login und Logout. Ganz wichtig: In Zeile 48 setzen wir den JWT Token unserer RestAPI als Authorization Header. Ohne diese Zeile würden alle zukünftigen Anfragen an die RestAPI nicht funktionieren!

Wenn Du genaueres über Vuex wissen möchtest, kannst Du das hier nachlesen.

// src/store.js

import Vue from 'vue';
import Vuex from 'vuex';
import Axios from 'axios';
import createPersistedState from 'vuex-persistedstate';

import AuthService from '@/services/AuthService.js';

Vue.use(Vuex);

const getDefaultState = () => {
	return {
		token: '',
		user: {}
	};
};

export default new Vuex.Store({
	strict: true,
	plugins: [createPersistedState()],
	state: getDefaultState(),
	getters: {
		isLoggedIn: state => {
			return state.token;
		},
		getUser: state => {
			return state.user;
		}
	},
	mutations: {
		SET_TOKEN: (state, token) => {
			state.token = token;
		},
		SET_USER: (state, user) => {
			state.user = user;
		},
		RESET: state => {
			Object.assign(state, getDefaultState());
		}
	},
	actions: {
		login: ({ commit, dispatch }, { token, user }) => {
			commit('SET_TOKEN', token);
			commit('SET_USER', user);

			// set auth header
			Axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
		},
		logout: ({ commit }) => {
			commit('RESET', '');
		}
	}
});

Damit der JWT Token auch bei jedem Aufruf übergeben wird, müssen wir die main.js noch wie folgt anpassen.

// src/main.js

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import Axios from 'axios';

Vue.config.productionTip = false;

// set auth header
Axios.defaults.headers.common['Authorization'] = `Bearer ${store.state.token}`;

new Vue({
	router,
	store,
	render: h => h(App)
}).$mount('#app');

6. Services für Registrierung und Login

Wir legen eine neue Datei AuthService.js an, um dort die Anfragen an unseren Server (RestAPI) zu machen. Dazu benötigen wir eine Funktion login(credentials) für den Login und die Funktion signUp(credentials) zum registrieren. Hier wird unser Package axios benötigt, welches wir unter Schritt 3 bereits installiert haben.

Die dritte Funktion getSecretContent() liefert uns den geheimen Inhalt wieder, den man nur angezeigt bekommt, wenn man eingeloggt ist.

// src/services/AuthService.js

import axios from 'axios';

const url = 'http://localhost:3000/api/';

export default {
	login(credentials) {
		return axios
			.post(url + 'login/', credentials)
			.then(response => response.data);
	},
	signUp(credentials) {
		return axios
			.post(url + 'sign-up/', credentials)
			.then(response => response.data);
	},
	getSecretContent() {
		return axios.get(url + 'secret-route/').then(response => response.data);
	}
};

7. Registrierungs Seite

Der wohl wichtigste Schritt: Die Registrierung neuer Benutzer. Dazu haben wir bereits im Router eine Route angelegt und erstellen jetzt dazu das passende Vue View. Hier haben wir ein einfaches Formular mit Benutzername, Password, Passwort Wiederholung und ein Button zum registrieren.

Beim Klick rufen wir die signUp(credentials) Funktion aus dem AuthService auf und übergeben die eingegebenen Benutzerdaten. Zusätzlich haben wir ein Feld, in dem Fehler- und Erfolgsmeldung automatisch ausgegeben werden: msg.

// src/views/SignUp.vue

<template>
	<div>
		<h1>Sign Up</h1>
		<input type="text" placeholder="Username" v-model="username" />
		<input type="text" placeholder="Password" v-model="password" />
		<input
			type="text"
			placeholder="Password (repeat)"
			v-model="password_repeat"
		/>
		<input type="button" @click="signUp" value="Sign Up" />
		<p v-if="msg">{{ msg }}</p>
	</div>
</template>
<script>
import AuthService from '@/services/AuthService.js';

export default {
	data() {
		return {
			username: '',
			password: '',
			password_repeat: '',
			msg: ''
		};
	},
	methods: {
		async signUp() {
			try {
				const credentials = {
					username: this.username,
					password: this.password,
					password_repeat: this.password_repeat
				};
				const response = await AuthService.signUp(credentials);
				this.msg = response.msg;
			} catch (error) {
				this.msg = error.response.data.msg;
			}
		}
	}
};
</script>

Optional kann man der Zeile 38 noch auf die Login Seite weiterleiten. Dazu kannst Du diesen Code verwenden:

this.$router.push('/');

Rufen wir diese Seite auf erhalten wir dieses Ergebnis mit vollem Funktionsumfang:

Vue Sign Up Demo

8. Login Seite

Beim Login haben wir einen ähnlichen Aufbau und rufen dieses mal die login(credentials) Funktion auf.

Wichtig ist in Zeile 36 der Aufruf von Vuex. Wir übergeben das Benutzerobjekt user und den Token token aus der HTTP Antwort und schreiben die Daten in Vuex.

Nach erfolgreicher Anmeldung wird in Zeile 38 auf die „geschützte Route“ weitergeleitet, die nur nach dem Login erreichbar sein soll.

// src/views/Login.vue

<template>
	<div>
		<h1>Login</h1>
		<input type="text" placeholder="Username" v-model="username" />
		<input type="text" placeholder="Password" v-model="password" />
		<input type="button" @click="login" value="Login" />
		<p v-if="msg">{{ msg }}</p>
	</div>
</template>
<script>
import AuthService from '@/services/AuthService.js';

export default {
	data() {
		return {
			username: '',
			password: '',
			msg: ''
		};
	},
	methods: {
		async login() {
			try {
				const credentials = {
					username: this.username,
					password: this.password
				};
				const response = await AuthService.login(credentials);
				this.msg = response.msg;

				const token = response.token;
				const user = response.user;

				this.$store.dispatch('login', { token, user });

				this.$router.push('/');
			} catch (error) {
				this.msg = error.response.data.msg;
			}
		}
	}
};
</script>

Und so sieht die Route in Aktion aus:

Vue Login Demo

9. Routen schützen

Die Registrierung und Anmeldung steht. Nun kommt der Part, in dem wir unsere / Route schützen wollen und nur mit gültigen Benutzerdaten zugänglich machen wollen. Dazu gehen wir in das entsprechende View und fügen ein paar Zeilen dazu, welche überprüfen, ob der Benutzer eingeloggt ist. Falls nicht, wird er auf die Login Seite weitergeleitet.

// src/views/Home.vue

<template>
	<div>
		<h1>Hi {{ username }}</h1>
		<p>{{ secretMessage }}</p>
		<input type="button" value="Logout" @click="logout" />
	</div>
</template>

<script>
import AuthService from '@/services/AuthService.js';

export default {
	data() {
		return {
			secretMessage: '',
			username: ''
		};
	},
	async created() {
		if (!this.$store.getters.isLoggedIn) {
			this.$router.push('/login');
		}

		this.username = this.$store.getters.getUser.username;

		this.secretMessage = await AuthService.getSecretContent();
	},
	methods: {
		logout() {
			this.$store.dispatch('logout');
			this.$router.push('/login');
		}
	}
};
</script>

Außerdem haben wir noch einen Logout Button hinzugefügt, um die aktuelle Sitzung zu beenden und der Benutzername wird auch ausgegeben. Natürlich ist alles nach belieben erweiterbar und anpassbar. Fertig sieht unser Login System dann so aus:

Vue Login System

10. Fazit

That’s it! Im zweiten Teil haben wir nun das Vue.js Frontend mit Hilfe von Vuex umgesetzt. Dabei haben wir sowohl eine Registrierungs Seite, eine Login Seite, „normale“ Seiten und durch einen Login geschützte Seiten erstellt. Solltest Du Teil 1: Erstellung der RestAPI mit Node.js und JWT noch nicht gelesen haben, kannst Du es direkt nachholen, um Deinem Login System eine Backend Komponente zu bieten. Damit haben wir ein komplettes Login System umgesetzt, welches Du für Deine Webanwendungen verwenden kannst. Danke für’s Lesen! 🙂

Beteilige dich an der Unterhaltung

5 Kommentare

  1. Rakon Dark: einfach das Tutorial mal richtig lesen und nicht nur copy-paste alles übernehmen. Dort steht wann und wo die AuthService.js von dir angelegt werden soll

  2. ab
    import AuthService from ‚@/services/AuthService.js‘;
    funktioniert gar nichts mehr ,
    auch sind in store router etc nach
    vue create client
    alles anders
    , vielleicht solltest du sagen , wennihr schon vue , node.js und vue cli könnte, dann könnte ihr das hier benutzen , aber eigentlich braucht ihr mich dann auch nicht .
    ergo dein tutorial ist im wichtigsten teil völlig wertlos .

    teste es doch einfach mal selber , weder gibt es services noch bringt es das anzulegen , weil AuthService wird eh nicht benutzt . sehe ich auch nicht in deinem Code irgendwie vorkommen .

    Also eins diese 100 tutorials wo der Autor , noch nie sein werk an etwas frischem getestet hat .
    alos lass den VUE teil einfach weg , den ab dem Punkt sieht das aus als hättest du das zusammengeschnitten ohne es selbst zu testen .

    1. Hi!
      Ob Du es glaubst oder nicht, aber dieses Projekt habe ich (bevor ich dieses Tutorial geschrieben habe!) 1:1 umgesetzt, ausgiebig getestet und den Code hier rein kopiert.
      Manchmal sind es nur ganz kleine Fehler, die dazu führen, dass nichts mehr funktioniert. Die kleinen Videos von den fertigen Funktionen stammen von dem gleichen Code.

      Viele Grüße
      LH

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