Catégories
Plugin et site web

Authentification dans Vue.js – Smashing Magazine

A propos de l'auteur

Precious Ndubueze est une développeur de logiciels qui passe la moitié de son temps dans sa tête lorsqu'elle ne se perd pas dans la résolution de problèmes ou l'écriture.
Plus à propos
Précieux

Chaque application Web qui gère des données spécifiques à l'utilisateur doit implémenter l'authentification. Savoir comment faire est important pour les développeurs Vue, et c'est ce sur quoi cet article vise à mettre en lumière. Ce tutoriel s'avérera utile pour les développeurs débutants qui souhaitent en savoir plus sur l'authentification dans Vue. Pour pouvoir suivre, vous devez avoir une bonne connaissance de Vue et Vuex.

L'authentification est une fonctionnalité très nécessaire pour les applications qui stockent des données utilisateur. Il s’agit d’un processus de vérification de l’identité des utilisateurs, garantissant que les utilisateurs non autorisés ne peuvent pas accéder aux données privées – des données appartenant à d’autres utilisateurs. Cela conduit à avoir des routes restreintes auxquelles seuls les utilisateurs authentifiés peuvent accéder. Ces utilisateurs authentifiés sont vérifiés en utilisant leurs informations de connexion (par exemple, nom d'utilisateur / e-mail et mot de passe) et en leur attribuant un jeton à utiliser pour accéder aux ressources protégées d'une application.

Dans cet article, vous allez découvrir:

  1. Configuration Vuex avec Axios
  2. Définition des itinéraires
  3. Gestion des utilisateurs
  4. Gestion du jeton expiré

Dépendances

Nous travaillerons avec les dépendances suivantes qui aident à l'authentification:

  • Axios
    Pour envoyer et récupérer des données depuis notre API
  • Vuex
    Pour stocker les données obtenues à partir de notre API
  • Vue-routeur
    Pour la navigation et la protection des routes

Nous travaillerons avec ces outils et verrons comment ils peuvent fonctionner ensemble pour fournir une fonctionnalité d'authentification robuste pour notre application.

L'API Backend

Nous allons créer un site de blog simple, qui utilisera cette API. Vous pouvez consulter les documents pour voir les points de terminaison et comment les demandes doivent être envoyées.

Dans la documentation, vous remarquerez que quelques points de terminaison sont attachés avec un verrou. C'est une façon de montrer que seuls les utilisateurs autorisés peuvent envoyer des demandes à ces terminaux. Les points de terminaison sans restriction sont les /register et /login points de terminaison. Une erreur avec le code d'état 401 doit être renvoyé lorsqu'un utilisateur non authentifié tente d'accéder à un point de terminaison restreint.

Après avoir connecté avec succès un utilisateur, le jeton d'accès ainsi que certaines données seront reçus dans l'application Vue, qui sera utilisée pour définir le cookie et attaché dans l'en-tête de la demande à utiliser pour les demandes futures. Le backend vérifiera l'en-tête de la demande chaque fois qu'une demande est faite à un point de terminaison restreint. Ne soyez pas tenté de stocker le jeton d'accès dans le stockage local.

(Grand aperçu)

Projet d'échafaudage

À l'aide de la CLI Vue, exécutez la commande ci-dessous pour générer l'application:

vue create auth-project

Naviguez dans votre nouveau dossier:

cd auth-project

Ajoutez le vue-router et installez plus de dépendances – vuex et axios:

vue add router
    npm install vuex axios

Maintenant, lancez votre projet et vous devriez voir ce que j'ai ci-dessous sur votre navigateur:

npm run serve

1. Configuration Vuex avec Axios

Axios est une bibliothèque JavaScript utilisée pour envoyer des requêtes depuis le navigateur vers les API. Selon la documentation Vuex;

«Vuex est un modèle de gestion d'état + bibliothèque pour les applications Vue.js. Il sert de magasin centralisé pour tous les composants d'une application, avec des règles garantissant que l'état ne peut être muté que de manière prévisible. »

Qu'est-ce que ça veut dire? Vuex est un magasin utilisé dans une application Vue qui nous permet de enregistrer données qui seront disponibles pour chaque composant et fourniront des moyens de modifier ces données. Nous utiliserons Axios dans Vuex pour envoyer nos requêtes et apporter des modifications à notre état (données). Axios sera utilisé dans Vuex actions envoyer GET et POST, la réponse obtenue sera utilisée pour envoyer des informations au mutations et qui met à jour nos données de magasin.

Pour gérer la réinitialisation de Vuex après l'actualisation, nous travaillerons avec vuex-persistedstate, une bibliothèque qui enregistre nos données Vuex entre les recharges de page.

npm install --save vuex-persistedstate

Créons maintenant un nouveau dossier store dans src, pour configurer le magasin Vuex. dans le store dossier, créez un nouveau dossier; modules et un dossier index.js. Il est important de noter que vous ne devez effectuer cette opération que si le dossier n’est pas créé automatiquement pour vous.

import Vuex from 'vuex';
import Vue from 'vue';
import createPersistedState from "vuex-persistedstate";
import auth from './modules/auth';

// Load Vuex
Vue.use(Vuex);
// Create store
export default new Vuex.Store({
  modules: {
    auth
  },
  plugins: (createPersistedState())
});

Ici, nous utilisons Vuex et importation d'une authentification module du modules dossier dans notre magasin.

Modules

Les modules sont différents segments de notre magasin qui gèrent ensemble des tâches similaires, notamment:

Avant de continuer, modifions notre main.js fichier.

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

axios.defaults.withCredentials = true
axios.defaults.baseURL = 'https://gabbyblog.herokuapp.com/';

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

Nous avons importé le store objet du ./store dossier ainsi que le package Axios.

Comme mentionné précédemment, le cookie de jeton d'accès et les autres données nécessaires obtenues de l'API doivent être définis dans les en-têtes de demande pour les demandes futures. Étant donné que nous utiliserons Axios pour faire des demandes, nous devons configurer Axios pour l'utiliser. Dans l'extrait ci-dessus, nous le faisons en utilisant axios.defaults.withCredentials = true, cela est nécessaire car par défaut, les cookies ne sont pas transmis par Axios.

aaxios.defaults.withCredentials = true est une instruction à Axios d'envoyer toutes les demandes avec des informations d'identification telles que; en-têtes d'autorisation, certificats clients TLS ou cookies (comme dans notre cas).

Nous définissons notre axios.defaults.baseURL pour notre demande Axios à notre API De cette façon, chaque fois que nous envoyons via Axios, il utilise cette URL de base. Avec cela, nous pouvons ajouter uniquement nos points de terminaison comme /register et /login à nos actions sans indiquer l'URL complète à chaque fois.

Maintenant à l'intérieur du modules dossier dans store créer un fichier appelé auth.js

//store/modules/auth.js

import axios from 'axios';
const state = {

};
const getters = {

};
const actions = {

};
const mutations = {

};
export default {
  state,
  getters,
  actions,
  mutations
};
state

Dans notre state dict, nous allons définir nos données, et leurs valeurs par défaut:

const state = {
  user: null,
  posts: null,
};

Nous définissons la valeur par défaut de state, qui est un objet qui contient user et posts avec leurs valeurs initiales comme null.

Actions

Les actions sont des fonctions utilisées pour commit une mutation pour changer l'état ou peut être utilisée pour dispatch c'est-à-dire appelle une autre action. Il peut être appelé dans différents composants ou vues et commet alors des mutations de notre état;

Enregistrer l'action

Notre Register l'action prend des données de forme, envoie les données à notre /register endpoint et affecte la réponse à une variable response. Ensuite, nous enverrons notre formulaire username et password à notre login action. De cette façon, nous connectons l'utilisateur après son inscription, afin qu'il soit redirigé vers le /posts page.

async Register({dispatch}, form) {
  await axios.post('register', form)
  let UserForm = new FormData()
  UserForm.append('username', form.username)
  UserForm.append('password', form.password)
  await dispatch('LogIn', UserForm)
},

Action de connexion

Voici où se déroule l'authentification principale. Lorsqu'un utilisateur renseigne son nom d'utilisateur et son mot de passe, il est transmis à un User qui est un objet FormData, le LogIn fonction prend le User objet et fait un POST demande à la /login endpoint pour connecter l'utilisateur.

le Login la fonction valide enfin le username à la setUser mutation.

async LogIn({commit}, User) {
  await axios.post('login', User)
  await commit('setUser', User.get('username'))
},

Créer une action post

Notre CreatePost l'action est une fonction qui prend post et l'envoie à notre /post endpoint, puis distribue le GetPosts action. Cela permet à l'utilisateur de voir ses publications après la création.

async CreatePost({dispatch}, post) {
  await axios.post('post', post)
  await dispatch('GetPosts')
},

Obtenir l'action des messages

Notre GetPosts action envoie un GET demande à notre /posts endpoint pour récupérer les messages dans notre API et commits setPosts mutation.

async GetPosts({ commit }){
  let response = await axios.get('posts')
  commit('setPosts', response.data)
},

Action de déconnexion

async LogOut({commit}){
  let user = null
  commit('logout', user)
}

Notre LogOut l'action supprime notre user à partir du cache du navigateur. Il le fait en validant un logout:

Les mutations
const mutations = {
    setUser(state, username){
        state.user = username
    },
    setPosts(state, posts){
        state.posts = posts
    },
    LogOut(state){
        state.user = null
        state.posts = null
    },
};

Chaque mutation prend le state et une valeur de l'action qui l'engage, mis à part Logout. La valeur obtenue est utilisée pour changer certaines parties ou tout ou comme dans LogOut remettez toutes les variables à zéro.

Getters

Les Getters sont des fonctionnalités permettant d'obtenir l'état. Il peut être utilisé dans plusieurs composants pour obtenir l'état actuel.
le isAuthenticatated la fonction vérifie si le state.user est défini ou nul et retourne true ou false respectivement. StatePosts et StateUser revenir state.posts et state.user respectivement valeur.

const getters = {
    isAuthenticated: state => !!state.user,    
    StatePosts: state => state.posts,
    StateUser: state => state.user,
};

Maintenant ton tout auth.js Le fichier doit ressembler à mon code sur GitHub.

Configuration des composants

1. NavBar.vue Et App.vue Composants

Dans ton src/components dossier, supprimez le HelloWorld.vue et un nouveau fichier appelé NavBar.vue.

C'est le composant de notre barre de navigation, il renvoie aux différentes pages de notre composant qui ont été acheminés ici. Chaque lien de routeur pointe vers une route / page sur notre application.

le v-if="isLoggedIn" est une condition pour afficher le Logout lien si un utilisateur est connecté et masquez le Register et Login itinéraires. Nous avons un logout méthode qui ne peut être accessible qu'aux utilisateurs connectés, elle sera appelée lorsque le Logout le lien est cliqué. Il enverra le LogOut action puis dirigez l'utilisateur vers la page de connexion.




Modifiez maintenant votre App.vue composant pour ressembler à ceci:




Ici, nous avons importé le composant NavBar que nous avons créé ci-dessus et placé dans la section modèle avant le .

2. Vues des composants

Les composants Views sont différentes pages de l'application qui seront définies sous un itinéraire et accessibles à partir de la barre de navigation. Pour commencer Accédez au views dossier, supprimez le About.vue composant et ajoutez les composants suivants:

Home.vue

Réecrit le Home.vue pour ressembler à ceci:



Cela affichera un texte de bienvenue aux utilisateurs lorsqu'ils visitent la page d'accueil.

Register.vue

C'est la page sur laquelle nous voulons que nos utilisateurs puissent s'inscrire sur notre application. Lorsque les utilisateurs remplissent le formulaire, leurs informations sont envoyées à l'API et ajoutées à la base de données puis connectées.

En regardant l'API, le /register endpoint nécessite un username, full_name et password de notre utilisateur. Créons maintenant une page et un formulaire pour obtenir ces informations:


dans le Register composant, nous devrons appeler le Register action qui recevra les données du formulaire.


Nous commençons par importer mapActions depuis Vuex, cela permet d'importer des actions de notre magasin vers le composant. Cela nous permet d'appeler l'action à partir du composant.

data() contient la valeur de l'état local qui sera utilisée dans ce composant, nous avons un form objet qui contient username, full_name et password, avec leurs valeurs initiales définies sur une chaîne vide. Nous avons également showError qui est un booléen, à utiliser pour afficher une erreur ou non.

dans le methods nous importons le Register action utilisant le Mapactions dans le composant, de sorte que Register l'action peut être appelée avec this.Register .

Nous avons une méthode de soumission qui appelle le Register action à laquelle nous avons accès en utilisant this.Register, l'envoyer this.form. Sinon error est rencontré nous utilisons this.$router pour envoyer l'utilisateur à la page de connexion. Sinon, nous définissons showError à vrai.

Après avoir fait cela, nous pouvons inclure un certain style.


Login.vue

Notre page de connexion est l'endroit où les utilisateurs enregistrés entreront leur username et password pour être authentifié par l'API et connecté à notre site.


Nous devons maintenant transmettre les données de notre formulaire à l'action qui envoie la demande, puis les pousser vers la page sécurisée Posts


Nous importons Mapactions et utilisez-le pour importer le LogIn action dans le composant, qui sera utilisé dans notre submit une fonction.

Après le Login action, l'utilisateur est redirigé vers le /posts page. En cas d'erreur, l'erreur est interceptée et ShowError est défini sur true.

Maintenant, un peu de style:


Posts.vue

Notre page Messages est la page sécurisée qui n'est disponible que pour les utilisateurs authentifiés. Sur cette page, ils ont accès aux publications de la base de données de l'API. Cela permet aux utilisateurs d'avoir accès aux publications et leur permet également de créer des publications sur l'API.


Dans le code ci-dessus, nous avons un formulaire pour que l'utilisateur puisse créer de nouveaux articles. L'envoi du formulaire devrait entraîner l'envoi du message à l'API – nous ajouterons bientôt la méthode qui le fera. Nous avons également une section qui affiche les publications obtenues à partir de l'API (au cas où l'utilisateur en aurait). Si l'utilisateur n'a pas de messages, nous affichons simplement un message indiquant qu'il n'y a pas de messages.

le StateUser et StatePosts les getters sont mappés, c'est-à-dire importés en utilisant mapGetters dans Posts.vue puis ils peuvent être appelés dans le modèle.


Nous avons un état initial pour form, qui est un objet qui a title et write_up car ses clés et les valeurs sont définies sur une chaîne vide. Ces valeurs changeront en tout ce que l'utilisateur entre dans le formulaire dans la section modèle de notre composant.

Lorsque l'utilisateur soumet le message, nous appelons le this.CreatePost qui reçoit l'objet de formulaire.

Comme vous pouvez le voir dans le created cycle de vie, nous avons this.GetPosts pour récupérer les publications lorsque le composant est créé.

Un peu de style,


2. Définition des itinéraires

Dans notre router/index.js fichier, importez nos vues et définissez des itinéraires pour chacune d'elles

import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '../store';
import Home from '../views/Home.vue'
import Register from '../views/Register'
import Login from '../views/Login'
import Posts from '../views/Posts'

Vue.use(VueRouter)
const routes = (
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/register',
    name: "Register",
    component: Register,
    meta: { guest: true },
  },
  {
    path: '/login',
    name: "Login",
    component: Login,
    meta: { guest: true },
  },
  {
    path: '/posts',
    name: Posts,
    component: Posts,
    meta: {requiresAuth: true},
  }
)
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

3. Gestion des utilisateurs

  • Utilisateurs non autorisés
    Si vous avez remarqué lors de la définition de nos itinéraires de publications, nous avons ajouté un meta clé pour indiquer que l'utilisateur doit être authentifié, nous devons maintenant avoir un router.BeforeEach garde de navigation qui vérifie si un itinéraire a meta: {requiresAuth: true} clé. Si un itinéraire a le meta clé, il vérifie le magasin pour un jeton; s'il est présent, il les redirige vers le login route.
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})
router.beforeEach((to, from, next) => {
  if(to.matched.some(record => record.meta.requiresAuth)) {
    if (store.getters.isAuthenticated) {
      next()
      return
    }
    next('/login')
  } else {
    next()
  }
})

export default router
  • Utilisateurs autorisés
    Nous avons également un meta sur le /register et /login itinéraires. le meta: {guest: true} empêche les utilisateurs connectés d'accéder aux itinéraires avec le guest meta.
router.beforeEach((to, from, next) => {
  if (to.matched.some((record) => record.meta.guest)) {
    if (store.getters.isAuthenticated) {
      next("/posts");
      return;
    }
    next();
  } else {
    next();
  }
});

En fin de compte, votre fichier devrait ressembler à ceci:

import Vue from "vue";
import VueRouter from "vue-router";
import store from "../store";
import Home from "../views/Home.vue";
import Register from "../views/Register";
import Login from "../views/Login";
import Posts from "../views/Posts";

Vue.use(VueRouter);

const routes = (
  {
    path: "/",
    name: "Home",
    component: Home,
  },
  {
    path: "/register",
    name: "Register",
    component: Register,
    meta: { guest: true },
  },
  {
    path: "/login",
    name: "Login",
    component: Login,
    meta: { guest: true },
  },
  {
    path: "/posts",
    name: "Posts",
    component: Posts,
    meta: { requiresAuth: true },
  },
);

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to, from, next) => {
  if (to.matched.some((record) => record.meta.requiresAuth)) {
    if (store.getters.isAuthenticated) {
      next();
      return;
    }
    next("/login");
  } else {
    next();
  }
});

router.beforeEach((to, from, next) => {
  if (to.matched.some((record) => record.meta.guest)) {
    if (store.getters.isAuthenticated) {
      next("/posts");
      return;
    }
    next();
  } else {
    next();
  }
});

export default router;

4. gestion des jetons expirés (demandes interdites)

Notre API est configurée pour expirer les jetons après 30 minutes, maintenant si nous essayons d'accéder au posts page après 30 minutes, nous obtenons un 403 erreur, ce qui signifie que nous devons nous reconnecter, nous allons donc définir un intercepteur qui lit si nous obtenons un 403 erreur puis il nous redirige vers le login page.
Ajoutez l'extrait ci-dessous après la déclaration d'URL par défaut Axios dans le main.js fichier.

axios.interceptors.response.use(undefined, function (error) {
  if (error) {
    const originalRequest = error.config;
    if (error.response.status === 401 && !originalRequest._retry) {
  
        originalRequest._retry = true;
        store.dispatch('LogOut')
        return router.push('/login')
    }
  }
})

Cela devrait amener votre code au même état que l'exemple sur GitHub.

Conclusion

Si vous avez pu suivre jusqu'à la fin, vous devriez maintenant être en mesure de créer une application frontale entièrement fonctionnelle et sécurisée. Vous en savez maintenant plus sur Vuex et sur la façon de l'intégrer à Axios, ainsi que sur la sauvegarde de ses données après le rechargement.

Ressources

Éditorial fracassant(ks, ra, il)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *