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 (c'est-à-dire 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 apprendre about:
- Configuration Vuex avec Axios
- Définition des routes
- Gestion des utilisateurs
- Gestion des jetons expirés
Dépendances
Nous allons travailler avec les dépendances suivantes qui aident à l'authentification:
- Axios [19659014] Pour envoyer et récupérer des données depuis notre API
- Vuex
Pour stocker les données obtenues depuis notre API - Vue-Router
Pour la navigation et la protection des routes
Nous travaillerons avec ces outils et voyez comment ils peuvent travailler 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 la documentation pour voir les points de terminaison et comment les demandes doivent être envoyées.
Dans la documentation, vous remarquerez que peu de 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 points de terminaison / register
et / login
. Une erreur avec le code d'état 401
doit être renvoyée lorsqu'un utilisateur non authentifié tente d'accéder à un point de terminaison restreint.
Après avoir réussi à se connecter à un utilisateur, le jeton d'accès ainsi que certaines données seront reçus dans l'application Vue , qui sera utilisé dans la configuration du cookie et joint 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.
Scaffold Project
En utilisant la CLI Vue, exécutez la commande ci-dessous pour générer l'application:
vue create auth-project
Accédez à votre nouveau dossier:
cd auth-project
Ajoutez la vue-router et installez plus de dépendances – vuex et axios:
vue add router
npm installer vuex axios
Lancez maintenant votre projet et vous devriez voir ce que j'ai ci-dessous sur votre navigateur:
npm run serve
1. Configuration de Vuex avec Axios
Axios est une bibliothèque JavaScript qui est utilisée pour envoyer des requêtes du navigateur aux API. D'après 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 cela signifie? Vuex est un magasin utilisé dans une application Vue qui nous permet de sauvegarder les données qui seront disponibles pour chaque composant et de fournir 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 les actions Vuex
pour envoyer GET
et POST
la réponse obtenue sera utilisée pour envoyer des informations aux mutations
et qui met à jour les données de notre magasin.
Pour gérer la réinitialisation de Vuex après l'actualisation, nous allons travailler avec vuex-persistedstate
une bibliothèque qui enregistre nos données Vuex entre les rechargements de page.
npm install --save vuex -état persistant
Créons maintenant un nouveau dossier store
dans src
pour configurer le store Vuex. Dans le dossier store
créez un nouveau dossier; modules
et un fichier index.js
. Il est important de noter que vous n’avez besoin de le faire que si le dossier n’est pas créé automatiquement pour vous.
import Vuex de «vuex»;
importer Vue depuis 'vue';
import createPersistedState de "vuex-persistedstate";
import auth de './modules/auth';
// Charger Vuex
Vue.use (Vuex);
// Créer un magasin
exporter le nouveau Vuex.Store par défaut ({
modules: {
auth
},
plugins: [createPersistedState()]
});
Ici, nous utilisons Vuex
et importons un module auth
du dossier modules
dans notre magasin.
Modules
] Les modules sont différents segments de notre boutique qui gèrent ensemble des tâches similaires, notamment:
Avant de continuer, éditons notre fichier main.js
.
import Vue from 'vue'
importer l'application depuis './App.vue'
importer un routeur depuis './router';
importer le magasin depuis './store';
importer des axios depuis 'axios';
axios.defaults.withCredentials = true
axios.defaults.baseURL = 'https://gabbyblog.herokuapp.com/';
Vue.config.productionTip = false
nouvelle Vue ({
boutique,
routeur,
rendu: h => h (App)
}). $ mount ('# application')
Nous avons importé l'objet store
du dossier ./ store
ainsi que du package Axios.
Comme mentionné précédemment, le cookie du jeton d'accès et d'autres données nécessaires ont été obtenus à partir de l'API doit être définie 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 requête Axios à notre API
De cette façon, chaque fois nous envoyons via Axios, il utilise cette URL de base. Avec cela, nous pouvons ajouter seulement nos points de terminaison comme / register
et / login
à nos actions sans indiquer l'URL complète à chaque fois.
Maintenant dans les modules
] dossier store
créer un fichier appelé auth.js
// store / modules / auth.js
importer des axios depuis 'axios';
état const = {
};
const getters = {
};
actions const = {
};
mutations const = {
};
export par défaut {
Etat,
getters,
Actions,
mutations
};
state
Dans notre state
dict, nous allons définir nos données et leurs valeurs par défaut:
const state = {
utilisateur: nul,
messages: 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 qui sont utilisées pour commettre
une mutation pour changer l'état ou peuvent être utilisées pour expédier
c'est-à-dire appeler une autre action. Il peut être appelé dans différents composants ou vues, puis commet des mutations de notre état;
Register Action
Notre action Register
prend la forme de données, envoie les données à notre / register
et attribue la réponse à une variable response
. Ensuite, nous enverrons notre formulaire nom d'utilisateur
et mot de passe
à notre action de connexion
. De cette façon, nous connectons l'utilisateur après son inscription, afin qu'il soit redirigé vers la page / posts
.
async Register ({dispatch}, form) {
attendre axios.post ('s'inscrire', formulaire)
laissez UserForm = new FormData ()
UserForm.append ('nom d'utilisateur', formulaire.username)
UserForm.append ('mot de passe', form.password)
attendre la distribution ('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, la fonction LogIn
prend l'objet User
et crée un POST
au point de terminaison / login
pour se connecter à l'utilisateur.
La fonction Login
valide enfin le nom d'utilisateur
dans le setUser
mutation.
async LogIn ({commit}, User) {
attendre axios.post ('login', Utilisateur)
attendre commit ('setUser', User.get ('nom d'utilisateur'))
},
Créer une action post
Notre action CreatePost
est une fonction qui prend le poste
et l'envoie à notre / poste
puis envoie l'action GetPosts
. Cela permet à l'utilisateur de voir ses messages après la création.
async CreatePost ({dispatch}, post) {
attendre axios.post ('post', post)
attendre la distribution ('GetPosts')
},
Action Get Posts
Notre action GetPosts
envoie une requête GET
à notre point de terminaison / posts
pour récupérer les messages dans notre API et commits mutation setPosts
.
async GetPosts ({commit}) {
laissez la réponse = attendre axios.get ('posts')
commit ('setPosts', response.data)
},
Action de déconnexion
async LogOut ({commit}) {
laissez user = null
commit ('déconnexion', utilisateur)
}
Notre action LogOut
supprime notre utilisateur
du cache du navigateur. Il le fait en validant une déconnexion
:
Mutations
const mutations = {
setUser (état, nom d'utilisateur) {
state.user = nom d'utilisateur
},
setPosts (état, messages) {
state.posts = messages
},
LogOut (état) {
state.user = null
state.posts = null
},
};
Chaque mutation prend l'état
et une valeur de l'action l'engageant, mis à part Déconnexion
. La valeur obtenue est utilisée pour changer certaines parties ou tout ou autre dans LogOut
remet toutes les variables à zéro.
Getters
Getters sont des fonctionnalités permettant d'obtenir l'état. Il peut être utilisé dans plusieurs composants pour obtenir l'état actuel.
La fonction isAuthenticatated
vérifie si le state.user
est défini ou nul et renvoie true
ou false
respectivement. StatePosts
et StateUser
renvoient state.posts
et state.user
respectivement value.
const getters = {
isAuthenticated: state => !! state.user,
StatePosts: état => state.posts,
StateUser: state => state.user,
};
Maintenant, tout votre fichier auth.js
devrait ressembler à mon code sur GitHub .
Configuration des composants
1. NavBar.vue
Et App.vue
Components
Dans votre dossier src / components
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 routé ici. Chaque lien de routeur pointe vers une route / page sur notre application.
Le v-if = "isLoggedIn"
est une condition pour afficher le lien Déconnexion
si un utilisateur est connecté et masquez les routes Register
et Login
. Nous avons une méthode déconnexion
qui ne peut être accessible qu'aux utilisateurs connectés, elle sera appelée lorsque le lien Déconnexion
sera cliqué. Il enverra l'action LogOut
et dirigera l'utilisateur vers la page de connexion.
Modifiez maintenant votre composant App.vue
pour qu'il ressemble à ceci:
Ici, nous avons importé le composant NavBar que nous avons créé ci-dessus et placé dans la section template avant le .
2. Composants de vues
Les composants de vues sont des pages différentes de l'application qui seront définies sous un itinéraire et accessibles à partir de la barre de navigation. Pour commencer Allez dans le dossier views
supprimez le composant About.vue
et ajoutez les composants suivants:
Home.vue
Réécrivez le Home. vue
pour ressembler à ceci:
Ceci affichera un texte de bienvenue aux utilisateurs lorsqu'ils visiteront la page d'accueil.
Register.vue
C'est la page que 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 point de terminaison / register
nécessite un nom d'utilisateur
] full_name
et mot de passe
de notre utilisateur. Créons maintenant une page et un formulaire pour obtenir ces informations:
Dans le registre
]nous devrons appeler l'action Register
qui recevra les données du formulaire.
Nous commençons par importer mapActions
depuis Vuex, ce que cela fait est 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 objet form
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 les méthodes
nous importons l'action Register
en utilisant Mapactions
dans le composant, de sorte que l'action Register
peut être appelée avec this.Register
.
Nous avons une méthode de soumission qui appelle Register
action à laquelle nous avons accès en utilisant this.Register
en l'envoyant this.form
. Si aucune erreur
n'est rencontrée, nous utilisons ceci. $ Router
pour envoyer l'utilisateur à la page de connexion. Sinon, nous définissons showError
sur true.
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 nom d'utilisateur
et mot de passe
pour s'authentifier par l'API et se connecter à notre site.
Nous devrons maintenant transmettre les données de notre formulaire à l'action qui envoie la demande, puis les pousser vers la page sécurisée Messages
Nous importons Mapactions
et l'utilisons pour importer l'action LogIn
dans le composant, qui sera utilisée dans notre fonction soumettre
.
Après le Connexion
l'utilisateur est redirigé vers la page / posts
. En cas d'erreur, l'erreur est interceptée et ShowError
est défini sur true.
Maintenant, quelques styles:
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 messages et leur permet également de créer des messages dans l'API.
Dans le code ci-dessus, nous avons un formulaire pour que l'utilisateur puisse créer de nouveaux messages. 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.
Les getters StateUser
et StatePosts
sont mappés c'est-à-dire importés en utilisant mapGetters
dans Posts.vue
et ils peuvent ensuite être appelés dans le modèle.
Nous avons un état initial pour formulaire
qui est un objet qui a title
et write_up
comme clés et les valeurs sont définies sur une chaîne vide . Ces valeurs changeront pour ce que l'utilisateur saisira 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 du formulaire.
] Comme vous pouvez le voir dans le cycle de vie créé
nous avons this.GetPosts
pour récupérer les messages lorsque le composant est créé.
Quelques styles,
2. Définition des routes
Dans notre fichier router / index.js
importez nos vues et définissez des routes pour chacune d'elles
import Vue from 'vue'
importer VueRouter depuis 'vue-router'
importer le magasin depuis '../store';
importer la page d'accueil depuis '../views/Home.vue'
Importer le registre depuis «../views/Register»
importation de connexion depuis «../views/Login»
importer des messages à partir de "../views/Posts"
Vue.use (VueRouter)
routes const = [
{
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},
}
]
routeur const = nouveau VueRouter ({
mode: 'histoire',
base: process.env.BASE_URL,
itinéraires
})
exporter le routeur par défaut
3. Gestion des utilisateurs
- Utilisateurs non autorisés
Si vous avez remarqué lors de la définition de nos routes de messages, nous avons ajouté une clémeta
pour indiquer que l'utilisateur doit être authentifié, nous avons maintenant besoin d'un routeur.
garde de navigation qui vérifie si une route possède la clémeta: {requiresAuth: true}
. Si une route a la clémeta
elle recherche un jeton dans le magasin; s'il est présent, il les redirige vers la routelogin
.
const router = new VueRouter ({
mode: 'histoire',
base: process.env.BASE_URL,
itinéraires
})
router.beforeEach ((to, from, next) => {
if (to.matched.some (record => record.meta.requiresAuth)) {
if (store.getters.isAuthenticated) {
prochain()
revenir
}
suivant ('/ login')
} autre {
prochain()
}
})
exporter le routeur par défaut
- Utilisateurs autorisés
Nous avons également une méta/ register
et/ login
. La méta: {guest: true}
empêche les utilisateurs connectés d'accéder aux routes avec la métaguest
.
router.beforeEach ((to, from, next) = > {
if (to.matched.some ((record) => record.meta.guest)) {
if (store.getters.isAuthenticated) {
suivant ("/ posts");
revenir;
}
prochain();
} autre {
prochain();
}
});
À la fin, votre fichier devrait ressembler à ceci :
import Vue from "vue";
importer VueRouter depuis "vue-router";
importer le magasin depuis "../store";
import Accueil de "../views/Home.vue";
importer le registre de "../views/Register";
importation de connexion depuis "../views/Login";
importer des messages depuis "../views/Posts";
Vue.use (VueRouter);
routes const = [
{
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 },
},
];
routeur const = nouveau VueRouter ({
mode: "historique",
base: process.env.BASE_URL,
itinéraires,
});
router.beforeEach ((to, from, next) => {
if (to.matched.some ((record) => record.meta.requiresAuth)) {
if (store.getters.isAuthenticated) {
prochain();
revenir;
}
suivant ("/ login");
} autre {
prochain();
}
});
router.beforeEach ((to, from, next) => {
if (to.matched.some ((record) => record.meta.guest)) {
if (store.getters.isAuthenticated) {
suivant ("/ posts");
revenir;
}
prochain();
} autre {
prochain();
}
});
exporter le routeur par défaut;
4.Handling Expired Token (Forbidden Requests)
Notre API est configurée pour expirer les jetons après 30 minutes, maintenant si nous essayons d'accéder à la page posts
après 30 minutes, nous obtenons un 403
ce qui signifie que nous devons nous reconnecter, nous allons donc définir un intercepteur qui lit si nous obtenons une erreur 403
puis il nous redirige vers la page de connexion
.
Ajoutez l'extrait ci-dessous après la déclaration d'URL par défaut d'Axios dans le fichier main.js
.
axios.interceptors.response.use (undefined, function (error) {
if (erreur) {
const originalRequest = error.config;
if (error.response.status === 401 &&! originalRequest._retry) {
originalRequest._retry = vrai;
store.dispatch ('LogOut')
return router.push ('/ login')
}
}
})
Cela devrait ramener votre code au même état que l'exemple sur GitHub .
Conclusion
Si vous avez pu suivre jusqu'à la fin, vous devriez maintenant pouvoir construire une application frontale entièrement fonctionnelle et sécurisée. Vous en savez maintenant plus sur Vuex et sur la manière de l’intégrer à Axios, ainsi que sur la façon de sauvegarder ses données après le rechargement.
Resources
Source link