Authentifizierung mit Vue und RESTful APIs meistern

Avatar of David Atanda
David Atanda am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Authentifizierung (Einloggen!) ist ein entscheidender Teil vieler Websites. Lassen Sie uns sehen, wie man dies auf einer Website mit Vue umsetzt, genauso wie es mit jedem benutzerdefinierten Backend erfolgen kann. Vue kann die Authentifizierung nicht allein durchführen – wir benötigen dafür einen anderen Dienst, wir werden also einen anderen Dienst (Firebase) dafür verwenden, und dann das gesamte Erlebnis in Vue integrieren.

Die Authentifizierung funktioniert bei Single Page Applications (SPAs) ganz anders als bei Websites, die jede Seite neu laden. Sie *müssen* keine SPA mit Vue erstellen, aber wir werden dies in diesem Tutorial tun. 

Hier ist der Plan. Wir erstellen eine Benutzeroberfläche für Benutzer zum Einloggen, und die übermittelten Daten werden an einen Server gesendet, um zu prüfen, ob der Benutzer existiert. Wenn ja, erhalten wir ein Token. Das ist sehr nützlich, da es auf unserer gesamten Website verwendet wird, um zu prüfen, ob der Benutzer noch angemeldet ist. Wenn nein, kann sich der Benutzer immer registrieren. Mit anderen Worten, es kann in vielen bedingten Kontexten verwendet werden. Darüber hinaus, wenn wir Informationen vom Server benötigen, die eine Anmeldung erfordern, wird das Token über die URL an den Server gesendet, damit Informationen nur an angemeldete Benutzer gesendet werden.

Die vollständige Demo dieses Tutorials finden Sie auf GitHub für diejenigen, die den Code gerne durchlesen. Der Rest von uns kann dem Artikel folgen. Die Startdatei ist ebenfalls auf GitHub, damit Sie uns beim gemeinsamen Programmieren folgen können. 

Nachdem Sie das Repository heruntergeladen haben, führen Sie npm install in Ihrem Terminal aus. Wenn Sie diese Anwendung komplett selbst erstellen möchten, müssen Sie Vuex, Vue Router und axios installieren. Wir werden für dieses Projekt auch Firebase verwenden, nehmen Sie sich also einen Moment Zeit, um ein kostenloses Konto einzurichten und dort ein neues Projekt zu erstellen.

Nachdem Sie das Projekt zu Firebase hinzugefügt haben, gehen Sie zum Authentifizierungsbereich und richten Sie eine Anmeldemethode ein, bei der wir den traditionellen E-Mail/Passwort-Anbieter verwenden werden, der auf unseren Firebase-Servern gespeichert wird.

Danach gehen wir zur Firebase Auth REST API-Dokumentation, um unsere Registrierungs- und Anmelde-API-Endpunkte zu erhalten. Wir benötigen einen API-Schlüssel, um diese Endpunkte in unserer App zu verwenden, und dieser ist in den Firebase-Projekteinstellungen zu finden.

Firebase bietet Authentifizierung über das SDK an, aber wir verwenden die Auth-API, um die Authentifizierung über beliebige benutzerdefinierte Backend-Server zu demonstrieren.

In unserer Startdatei haben wir das Registrierungsformular unten. Wir halten die Dinge hier ziemlich einfach, da wir uns auf das Erlernen der Konzepte konzentrieren.

<template>
  <div id="signup">
    <div class="signup-form">
      <form @submit.prevent="onSubmit">
        <div class="input">
          <label for="email">Mail</label>
          <input
             type="email"
             id="email"
             v-model="email">
        </div>
        <div class="input">
          <label for="name">Your Name</label>
          <input
            type="text"
            id="name"
            v-model.number="name">
        </div>
        <div class="input">
          <label for="password">Password</label>
          <input
            type="password"
            id="password"
            v-model="password">
        </div>
        <div class="submit">
          <button type="submit">Submit</button>
        </div>
      </form>
    </div>
  </div>
</template>

Wenn wir nicht mit einer SPA arbeiten würden, würden wir natürlich axios verwenden, um unsere Daten innerhalb des Skript-Tags wie folgt zu senden

axios.post('https://identitytoolkit.googleapis.com/v1/account
  s:signUp?key=[API_KEY]', {
    email: authData.email,
    password: authData.password,
    returnSecureToken: true
  })
  .then(res => {
    console.log(res)
  })
  .catch(error => console.log(error))        
  }
}

Registrieren und Einloggen

Die Arbeit mit einer SPA (in diesem Fall Vue) unterscheidet sich stark vom oben genannten Ansatz. Stattdessen senden wir unsere Autorisierungsanfragen über Vuex in unseren Aktionen in der Datei store.js. Wir tun dies, weil wir möchten, dass die gesamte App über jede Änderung des Authentifizierungsstatus des Benutzers informiert ist.

actions: {
  signup ({commit}, authData) {
    axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]', {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      router.push("/dashboard")
    })
    .catch(error => console.log(error))
  },
  login ({commit}, authData) {
    axios.post(https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]', {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      router.push("/dashboard")
    })
    .catch(error => console.log(error))
  }
}

Wir können im Grunde das Gleiche für die Anmeldemethode verwenden, aber stattdessen den Anmelde-API-Endpunkt nutzen. Dann übergeben wir sowohl die Registrierung als auch das Einloggen von den Komponenten an ihre jeweiligen Aktionen im Store.

methods : { 
  onSubmit () {
    const formData = {
      email : this.email,
      name : this.name,     
      password : this.password
    }
    this.$store.dispatch('signup', formData)
    }
  }
}

formData enthält die Daten des Benutzers.

methods : {
  onSubmit () {
    const formData = {
      email : this.email,
      password : this.password
    }
    this.$store.dispatch('login', {email: formData.email, password: formData.password})
  }
}

Wir nehmen die Authentifizierungsdaten (d. h. das Token und die Benutzer-ID), die vom Registrierungs-/Anmeldeformular empfangen wurden, und verwenden sie als Zustand mit Vuex. Anfangs wird dies null ergeben.

state: {
  idToken: null,
  userId: null,
  user: null
}

Wir erstellen nun eine neue Methode namens authUser in den Mutationen, die die aus der Antwort gesammelten Daten speichert. Wir müssen den Router in den Store importieren, da wir ihn später benötigen werden.

import router from '/router'


mutations : {
  authUser (state, userData) {
    state.idToken = userData.token
    state.userId = userData.userId
  }
}

Innerhalb des .then-Blocks in den Registrierungs-/Anmeldemethoden in unseren Aktionen übergeben wir unsere Antwort an die gerade erstellte authUser-Mutation und speichern sie im lokalen Speicher.

actions: {
  signup ({commit}, authData) {
    axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]'), {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      commit('authUser', {
        token: res.data.idToken,
        userId: res.data.localId
      })
      localStorage.setItem('token', res.data.idToken)
      localStorage.setItem('userId', res.data.localId)
      router.push("/dashboard")
    })
    .catch(error => console.log(error))
  },
  login ({commit}, authData) {
    axios.post('https://identitytoolkit.googleapis.com/v1/accounts:signIn?key=[API_KEY]'), {
      email: authData.email,
      password: authData.password,
      returnSecureToken: true
    })
    .then(res => {
      console.log(res)
      commit('authUser', {
        token: res.data.idToken,
        userId: res.data.localId
      })
        localStorage.setItem('token', res.data.idToken)
        localStorage.setItem('userId', res.data.localId)
        router.push("/dashboard")
      })
    .catch(error => console.log(error))
  }
}

Einrichtung eines Auth-Guards

Nachdem wir nun unser Token innerhalb der Anwendung gespeichert haben, werden wir dieses Token bei der Einrichtung unseres Auth-Guards verwenden. Was ist ein Auth-Guard? Er schützt das Dashboard vor unbefugten Benutzern, die ohne Token darauf zugreifen.

Zuerst gehen wir in unsere Routendatei und importieren den Store. Der Store wird wegen des Tokens importiert, das den Anmeldestatus des Benutzers bestimmt.

import store from './store.js'

Dann gehen wir innerhalb unseres Routen-Arrays zum Dashboard-Pfad und fügen die Methode beforeEnter hinzu, die drei Parameter erhält: to, from und next. Innerhalb dieser Methode sagen wir einfach, dass wenn die Tokens gespeichert sind (was automatisch geschieht, wenn authentifiziert), dann next aufgerufen wird, was bedeutet, dass die Navigation zur angegebenen Route fortgesetzt wird. Andernfalls leiten wir den nicht authentifizierten Benutzer zurück zur Registrierungsseite.

{
  path: '/dashboard',
  component: DashboardPage,
  beforeEnter (to, from, next) {
    if (store.state.idToken) {
      next()
    } 
    else {
      next('/signin')
    }
  }
}

Erstellung des UI-Zustands

Zu diesem Zeitpunkt können wir das Dashboard immer noch in der Navigation sehen, egal ob wir angemeldet sind oder nicht, und das ist nicht das, was wir wollen. Wir müssen eine weitere Methode unter den Gettern namens ifAuthenticated hinzufügen, die prüft, ob das Token in unserem Zustand null ist, und dann die Navigationselemente entsprechend aktualisiert.

getters: {
  user (state) {
    return state.user
  },
  ifAuthenticated (state) {
    return state.idToken !== null
  }
}

Als Nächstes öffnen wir die Header-Komponente und erstellen eine Methode namens auth innerhalb der computed-Eigenschaft. Diese wird zu den ifAuthenticated-Gettern im Store aufgerufen, die wir gerade erstellt haben. ifAuthenticated gibt false zurück, wenn kein Token vorhanden ist, was automatisch bedeutet, dass auth ebenfalls null wäre und umgekehrt. Danach fügen wir einen v-if hinzu, um zu prüfen, ob auth null ist oder nicht, und bestimmen so, ob die Dashboard-Option in der Navigation angezeigt wird.

<template>
  <header id="header">
    <div class="logo">
      <router-link to="/">Vue Authenticate</router-link>
    </div>
    <nav>
      <ul>
        <li v-if='auth'>
          <router-link to="/dashboard">Dashboard</router-link>
        </li>
        <li  v-if='!auth'>
          <router-link to="/signup">Register</router-link>
        </li>
        <li  v-if='!auth'>
          <router-link to="/signin">Log In</router-link>
        </li>
      </ul>
    </nav>
  </header>
</template>
<script>
  export default {
    computed: {
      auth () {
        return this.$store.getters.ifAuthenticated
      }
    },
  }
</script>

Ausloggen

Was wäre eine Anwendung ohne Ausloggen-Button? Lassen Sie uns eine neue Mutation namens clearAuth erstellen, die sowohl das Token als auch die userId auf null setzt.

mutations: {
  authUser (state, userData) {
    state.idToken = userData.token
    state.userId = userData.userId
  },
  clearAuth (state) {
    state.idToken = null
    state.userId = null
  }
}

Dann übergeben wir in unserer logout-Aktion an clearAuth, löschen den lokalen Speicher und fügen router.replace('/') hinzu, um den Benutzer nach dem Ausloggen korrekt weiterzuleiten.

Zurück zur Header-Komponente. Wir haben eine onLogout-Methode, die unsere logout-Aktion im Store aufruft. Dann fügen wir ein @click zum Button hinzu, der die onLogout-Methode aufruft, wie wir unten sehen können

<template>
  <header id="header">
    <div class="logo">
      <router-link to="/">Vue Authenticate</router-link>
    </div>
    <nav>
      <ul>
        <li v-if='auth'>
          <router-link to="/dashboard">Dashboard</router-link>
        </li>
        <li  v-if='!auth'>
          <router-link to="/signup">Register</router-link>
        </li>
        <li  v-if='!auth'>
          <router-link to="/signin">Log In</router-link>
        </li>
         <li  v-if='auth'>
          <ul @click="onLogout">Log Out</ul>
        </li>
      </ul>
    </nav>
  </header>
</template>
<script>
  export default {
    computed: {
      auth () {
        return this.$store.getters.ifAuthenticated
      }
    },
    methods: {
      onLogout() {
        this.$store.dispatch('logout')
      }
    }
  }
</script>

Automatisches Einloggen? Klar!

Wir sind fast fertig mit unserer App. Wir können uns anmelden, einloggen und ausloggen, mit all den UI-Änderungen, die wir gerade vorgenommen haben. Aber wenn wir unsere App aktualisieren, verlieren wir die Daten und werden ausgeloggt, was bedeutet, dass wir von vorne beginnen müssen, da wir unser Token und unsere ID in Vuex gespeichert haben, was JavaScript ist. Das bedeutet, dass alles in der App im Browser neu geladen wird, wenn aktualisiert wird. 

Was wir tun werden, ist, das Token aus unserem lokalen Speicher abzurufen. Indem wir das tun, können wir das Token des Benutzers im Browser haben, unabhängig davon, wann wir das Fenster aktualisieren, und den Benutzer sogar automatisch einloggen, solange das Token noch gültig ist.

Erstellen Sie eine neue Aktionsmethode namens AutoLogin, in der wir das Token und userId aus dem lokalen Speicher abrufen, nur wenn der Benutzer eines hat. Dann übergeben wir unsere Daten an die authUser-Methode in den Mutationen.

actions : {
  AutoLogin ({commit}) {
    const token = localStorage.getItem('token')
    if (!token) {
      return
    }
    const userId = localStorage.getItem('userId')
    const token = localStorage.getItem('token')
    commit('authUser', {
      idToken: token,
      userId: userId
    })
  }
}

Dann gehen wir zu unserer App.vue und erstellen eine created-Methode, in der wir autoLogin aus unserem Store aufrufen, wenn die App geladen wird.

created () {
  this.$store.dispatch('AutoLogin')
}

Juhu! Damit haben wir die Authentifizierung erfolgreich in unserer App implementiert und können nun mit npm run build bereitstellen. Schauen Sie sich die Live-Demo an, um sie in Aktion zu sehen.

Die Beispiel-Website dient ausschließlich Demonstrationszwecken. Bitte teilen Sie keine echten Daten, wie Ihre echten E-Mail-Adressen und Passwörter, während Sie die Demo-App testen.