Introduction
Récemment je suis tombé sur ce post Vue JS User Authentication de Microsoft paru en décembre 2020. Ce post me semblait inutilement complexe, utilisant VueX, et ne rendant pas vraiment homage à la simplicité de VueJS & Pinia.
Je me suis dit que ça pourrait être intéressant de revisiter cette problématique en Vue 3 avec Pinia.
Ensemble, partons de 0 et voyons comment mettre en place l'authentification au travers de Microsoft Azure depuis Vue 3.
Installation de Vue
Comme indiqué dans la documentation de Vue nous allons lancer les commandes suivantes pour initialiser un nouveau projet :
$ npm create vue@latest
Pour la demo, nous allons créer le projet vue3-mslogin-demo
avec les paramètres suivants
✔ Project name: … vue3-mslogin-demo
✔ Add TypeScript? … No
✔ Add JSX Support? … No
✔ Add Vue Router for Single Page Application development? … No
✔ Add Pinia for state management? … Yes
✔ Add Vitest for Unit testing? … No
✔ Add an End-to-End Testing Solution? … No
✔ Add ESLint for code quality? … Yes
✔ Add Prettier for code formatting? … Yes
Reste enfin à lancer le projet :
$ cd vue3-mslogin-demo
$ npm install
$ npm run format # Optionnel
$ npm run dev
Pour la suite, veillez à bien faire pointer votre navigateur vers http://localhost:5173/ afin d'éviter les erreurs de redirection Microsoft qui peuvent arriver si vous pointez sur
http://127.0.0.1:5173
Par défaut, l'assistant de création de projet va générer des classes, des composants et un store Pinia pour vous aider à prendre vueJS en main. Nous ne nous en servirons pas pour la demo, mais vous pourrez toujours aller y jeter un coup d'oeil. Pour le moment, afin de simplifier les choses aux maximum, nous allons désactiver les styles.
Pour cela, allez dans le fichier /src/main.js
et mettez simplement la 1ère ligne import './assets/main.css
en commentaire
Nous allons aussi en profiter pour simplifier le composant principal /src/App.vue
au maximum :
<script setup>
import MsLogin from './components/MsLogin.vue';
</script>
<template>
<MsLogin></MsLogin>
</template>
Enfin, nous allons réaliser un composant vide dans le fichier ./components/MsLogin.vue
<template>
This is an empty component...
</template>
Après avoir lancer un npm run dev
et en vous rendant sur http://localhost:5173/ vous devriez avoir l'affichage suivant :
Création des variables d'environnement pour l’authentification
Vite
permet de définir des variables d'environnement qui seront injectées dans le code au moment du run dev
ou du run build
. C'est très pratique pour permettre la modification rapide de certaines données sans aller fouiller dans le code. C'est aussi une bonne pratique de sortir les données sensibles du code pour éviter qu'elles ne se retrouvent dans l'historique du Git.
Créez un fichier .env
à la racine du projet avec le contenu suivant :
#.env
VITE_MS_CLIENT_ID='YOUR_APPLICATION_CLIENT_ID'
VITE_MS_TENANT_ID='YOUR_APPLICAITON_TENANT_ID'
Par convention, chez NCI excluons toujours les fichier .env
de notre GIT. Pour ce faire, il suffit d'ajouter la ligne suivante à la fin du fichier .gitignore
(...)
.env
Pour permettre aux autres développeurs de connaître ces variables et de les redéfinir, nous réalisons toujours une copie du fichier .env
, sans aucune clé afin de rapidement remonter le projet :
cp .env .env.sample
RAPPEL : Pensez à bien vérifier qu'aucune information sensible ne reste dans le fichier
.env.sample
avant de le commit sur le projet !
Dans le code, le contenu de ces variables pourra être récupéré comme ceci :
// Exemple d'utilisation d'une variable d'environnement avec Vite
const clientId = import.meta.env.VITE_MS_CLIENT_ID
const tenantId = import.meta.env.VITE_MS_TENANT_ID
Enregistrement d'une application dans Microsoft Azure
Maintenant que nous avons créé notre application en Vue, nous allons l'enregistrer dans Azure. Pour cela rendez-vous sur le portail d'Azure et authentifiez vous, puis dans le menu en haut à gauche choisissez Microsoft Entra ID
Dans la vue d'ensemble, cliquez sur le bouton Ajouter puis Inscription d'application
Dans le masque d'enregistrement de l'application spécifiez :
- Le nom de votre application :
vue3-mslogin-demo
- Le type de compte qui pourra s'y connecter :
Tous les comptes, 3eme option
- L'URI de redirection :
- Type d'application :
SPA (Single Page Application)
- URL :
http://localhost:5173
- Type d'application :
Validez ensuite le formulaire. Azure va enregistrer votre application et vous affichera la page d'information de cette application fraîchement créée.
Vous pouvez maintenant copier le tokens du champs ID d'application (client)
dans votre .env sur VITE_MS_CLIENT_ID
et l'ID d'annuaire (locataire)
sur VITE_MS_TENANT_ID
situés sur la page d'accueil de votre application dans Azure.
Création du store msAuthStore
Pour permettre à Vue d'authentifier les utilisateurs Microsoft, nous allons réaliser un store dédié. Ce store va permettre aux composants qui l'importent de réaliser une authentification via Microsoft Azure au moyen d'un package créé par Microsoft.
Quand l'authentification aura réussie, la variable account
du store contiendra les informations de l'utilisateur. Chaque composants intégrant ce store pourra alors avoir accès à ces informations.
Pour commencer, installons la librairie Microsoft qui va nous aider à connecter les utilisateurs :
$ npm install @azure/msal-browser -D
Pour ce store, j'ai choisi d'utiliser l'Option API afin d'en simplifier la compréhension et la lecture.
Créez un fichier ./stores/msAuthStore.js
avec le contenu suivant :
import { defineStore } from 'pinia'
import { PublicClientApplication } from '@azure/msal-browser';
export const useMsAuthStore = defineStore('msAuthStore', {
// ---------------------------------------------------------------------
state: () => ({
clientId: import.meta.env.VITE_MS_CLIENT_ID, // Application Client ID
tenantId: import.meta.env.VITE_MS_TENANT_ID, // Application Directory / Tenant ID
cacheLocation: 'localStorage', // Cache location used by MSAL
instance : null, // Public Client Application instance
account : null, // User account
}),
// ---------------------------------------------------------------------
getters: {
// Is the user signed in?
isSignedIn: (state) => !!state.account
},
// ---------------------------------------------------------------------
actions: {
// Configure the Public Client Application instance
config() {
this.instance = new PublicClientApplication({
auth: {
clientId: this.clientId,
authority: `https://login.microsoftonline.com/${this.tenantId}`,
},
cache: {
cacheLocation: this.cacheLocation,
},
})
},
async loadCache() {
if (!this.instance) this.config();
const accounts = await this.instance?.getAllAccounts();
if (!accounts || accounts.length == 0) return;
this.account = accounts[0];
},
// Sign in the user
async signIn() {
if (!this.instance) this.config();
await this.instance.initialize();
await this.instance.handleRedirectPromise();
await this.instance.loginPopup({})
const myAccounts = this.instance.getAllAccounts();
this.account = myAccounts[0];
},
// Sign out the user
signOut() {
this.account = null;
}
},
})
Ce store va utiliser les variables d'environnement et la librairie Microsoft pour authentifier l'utilisateur.
Outre l'accès a la variable account
contenant les informations de l'utilisateur, il dispose d'un getter isSignedIn
qui reverra true
ou false
selon que l'utilisateur est connecté ou non.
Il dispose enfin de quatres méthodes :
- la première permet de configurer l'instance d'authentification,
- la seconde va permettre de vérifier au chargement du composant si l'utilisateur a déjà été authentifié via le cache (ici le localStorage est utilisé).
- La troisième permet de connecter l'utilisateur (signIn)
- La dernière permet de déconnecter (signOut) l'utilisateur de l'application (sans pour autant le déconnecter de son compte Microsoft).
Vous noterez sans doute l'absence de Try/Catch : je préfère les réaliser dans les pages ou les composants ce qui est rendu possible par l'utilisation des fonctions asynchrones. Pour la démo, je ne les inclus pas, toujours dans un objectif de lisibilité.
Creation du composant d'authentification
Enfin viens le moment de réaliser le composant qui va réaliser l'authentification via le Store Pinia.
<script setup>
import { onMounted } from 'vue';
import { useMsAuthStore } from "@/stores/msAuthStore";
const msAuthStore = useMsAuthStore();
onMounted(() => {
msAuthStore.loadCache()
});
</script>
<template>
<button @click="msAuthStore.signIn()" v-show="!msAuthStore.isSignedIn"> SignIn </button>
<button @click="msAuthStore.signOut()" v-show="msAuthStore.isSignedIn"> SignOut </button>
<div v-if="msAuthStore.isSignedIn">
Congratulations!<br />
You are logged as <b>{{ msAuthStore.account?.name }}</b> {{ msAuthStore.account?.email }}
</div>
</template>
Dans la partie <script setup>
, on charge le store. C'est réalisé via ces deux lignes :
import { useMsAuthStore } from "@/stores/msAuthStore";
const msAuthStore = useMsAuthStore();
Il est alors possible d'utiliser directement le store via la variable msAuthStore
dans le template.
Notez le onMounted
, qui au chargement du composant, va demander à pinia de regarder si l'utilisateur est déjà connecté.
Vous devriez avoir cet affichage :
En cliquant sur le bouton, une fenêtre de connexion Microsoft devrait s'ouvrir. Un fois connecté vous devriez avoir un affichage de ce style :
Et voilà !
Conclusion
J'espère que ce petit bout de code vous aura permis de voir à quel point il est trivial de réaliser une authentification Azure avec Vue JS.
Au plaisir de se recroiser au détours de nouveaux tutoriels.