@amsom-habitat/user-manager
v1.12.0
Published
Gestionnaire centralisé d'authentification utilisateur pour les applications AMSOM Habitat.
Downloads
464
Readme
@amsom-habitat/user-manager
Gestionnaire centralisé d'authentification utilisateur pour les applications AMSOM Habitat.
🎯 Objectifs
- Gestion unifiée : Gérer les utilisateurs de la même manière sur tous les outils
- Token partagé : Partage du token JWT via cookies entre les sites du même domaine
- Réactivité : Synchronisation bidirectionnelle automatique avec les stores (Pinia/Vue)
- Cross-tab : Détection automatique des changements de token depuis d'autres onglets
📦 Installation
npm install @amsom-habitat/user-manager🚀 Utilisation de base
Configuration initiale
import userManager from '@amsom-habitat/user-manager'
// Configuration (dans main.js)
userManager.setLoginPageUrl('/login')
userManager.setDefaultLoginUrl('https://api.example.com/login')
userManager.setDefaultDomain('example.com')
userManager.setRoleHierarchy({
ROLE_ADMIN: ['ROLE_USER']
})
userManager.setRoleKey('mon-application')Authentification
// Login
const credentials = {
_username: '[email protected]',
_password: 'password123'
}
userManager.login(credentials)
.then(token => {
console.log('Connecté avec succès')
})
.catch(error => {
console.error('Erreur de connexion:', error)
})
// Logout
userManager.logout()
// Vérifier si connecté
if (userManager.isLogged()) {
console.log('Utilisateur connecté')
}
// Redirection vers la page de login
userManager.goToLoginPage() // Sauvegarde l'URL actuelle pour redirection après loginGestion du token
// Récupérer le token
const token = userManager.getToken()
// Définir un token manuellement
userManager.setToken(token, expirationTimestamp, domain)
// Décoder le token
const payload = userManager.getDecodedToken()
console.log(payload.login, payload.email, payload.roles)
// Vérifier la validité
if (userManager.isTokenValid()) {
console.log('Token valide et non expiré')
}
// Temps restant avant expiration (en secondes)
const remaining = userManager.getTokenTimeRemaining()
console.log(`Token expire dans ${remaining} secondes`)Gestion des rôles
// Récupérer les rôles
const roles = userManager.getRoles()
// Vérifier un rôle (avec hiérarchie)
if (userManager.isGranted('ROLE_ADMIN')) {
console.log('Utilisateur admin')
}⚡ Nouvelles fonctionnalités - Réactivité (v1.12.0)
Synchronisation automatique avec Pinia
// stores/user.js
import { defineStore } from 'pinia'
import userManager from '@amsom-habitat/user-manager'
let unwatchTokenCallback = null
export default defineStore('user', {
state: () => ({
token: userManager.getToken(),
}),
getters: {
isLogged: (state) => userManager.isLogged(state.token),
isTokenValid: (state) => userManager.isTokenValid(state.token),
tokenTimeRemaining: (state) => userManager.getTokenTimeRemaining(state.token),
},
actions: {
initTokenSync() {
// Active la synchronisation bidirectionnelle
unwatchTokenCallback = userManager.watchToken((newToken) => {
if (newToken !== this.token) {
console.log('Token synchronisé depuis userManager')
this.token = newToken
}
})
},
stopTokenSync() {
if (unwatchTokenCallback) {
unwatchTokenCallback()
unwatchTokenCallback = null
}
},
logout() {
this.token = null
userManager.logout()
},
},
})Initialisation dans l'application
// App.vue
import useUserStore from '@/stores/user'
export default {
setup() {
const userStore = useUserStore()
return { userStore }
},
mounted() {
// Initialise la synchronisation bidirectionnelle
this.userStore.initTokenSync()
},
beforeUnmount() {
// Nettoie les watchers
this.userStore.stopTokenSync()
},
watch: {
'userStore.token': function (newValue) {
// Synchronisation store → userManager
if (newValue) {
this.$userManager.setToken(newValue)
} else {
this.$userManager.logout()
}
}
},
}Watchers personnalisés
// Écouter les changements de token
const unwatch = userManager.watchToken((newToken, oldToken) => {
console.log('Token changé:', {
from: oldToken ? 'token présent' : 'pas de token',
to: newToken ? 'token présent' : 'pas de token'
})
// Réagir au changement
if (!newToken) {
// Utilisateur déconnecté
router.push('/login')
}
})
// Arrêter l'écoute
unwatch()
// Ou avec unwatchToken
userManager.unwatchToken(callback)Détection cross-tab
Les changements de token dans un onglet sont automatiquement détectés dans tous les autres onglets du même domaine :
// Onglet 1 : l'utilisateur se connecte
userManager.login(credentials)
// Onglet 2 : le watcher détecte automatiquement le nouveau token
// → L'interface se met à jour automatiquement
// → L'utilisateur est connecté dans tous les onglets📚 API complète
Configuration
| Fonction | Description |
|----------|-------------|
| setDefaultDomain(domain) | Définit le domaine pour les cookies |
| setDefaultExpirationToken(timestamp) | Définit l'expiration par défaut |
| setDefaultLoginUrl(url) | Définit l'URL de l'API de login |
| setLoginPageUrl(url) | Définit l'URL de la page de login |
| setRoleHierarchy(hierarchy) | Définit la hiérarchie des rôles |
| setRoleKey(key) | Définit la clé pour les rôles multi-apps |
| getDomain() | Récupère le domaine actuel |
Authentification
| Fonction | Description |
|----------|-------------|
| login(credentials, url?, domain?) | Connecte l'utilisateur |
| logout() | Déconnecte l'utilisateur |
| goToLoginPage(saveRedirect?) | Redirige vers la page de login |
| redirectionAfterLogin(callback) | Gère la redirection après login |
Gestion du token
| Fonction | Description |
|----------|-------------|
| getToken() | Récupère le token actuel |
| setToken(token, exp?, domain?) | Définit le token |
| getDecodedToken(token?) | Décode le token JWT |
| isTokenExpired(token?) | Vérifie si le token est expiré |
| isTokenValid(token?) | Vérifie si le token est valide ⭐ |
| getTokenTimeRemaining(token?) | Temps restant (secondes) ⭐ |
| refreshTokenCache() | Rafraîchit le cache ⭐ |
Rôles
| Fonction | Description |
|----------|-------------|
| getRoles(token?) | Récupère la liste des rôles |
| isGranted(role, token?) | Vérifie si un rôle est accordé |
| isLogged(token?) | Vérifie si l'utilisateur est connecté |
Réactivité ⭐ Nouveau
| Fonction | Description |
|----------|-------------|
| watchToken(callback) | Écoute les changements de token ⭐ |
| unwatchToken(callback) | Arrête l'écoute ⭐ |
| getWatchersCount() | Nombre de watchers actifs ⭐ |
⭐ = Nouvelles fonctionnalités v1.12.0
🔄 Flux de synchronisation
┌─────────────────┐
│ Cookie Token │ ◄──────────────────┐
│ (Partagé) │ │
└────────┬────────┘ │
│ │
│ getToken() setToken()
│ │
▼ │
┌─────────────────┐ watchToken() │
│ userManager │ ────────────────► │
│ (Cache) │ │
└────────┬────────┘ │
│ │
│ watchToken() │
│ │
▼ │
┌─────────────────┐ watch │
│ Store Pinia │ ─────────────────┘
│ (Réactif) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ Composants │
│ Vue │
└─────────────────┘🛡️ Sécurité
- Validation automatique des tokens avant utilisation
- Détection des tokens expirés dans le cache
- Protection contre les cookies trop volumineux
- Validation des paramètres des fonctions critiques
- Gestion sécurisée des erreurs
📝 Structure du token
interface TokenInterface {
typeUSer: string
login: string
nomComplet: string
email: string
nom: string
prenom: string
poste: string
departement: string
extras: Record<string, any>
roles: { [key: string]: string[] } | string[]
exp: number // Expiration du token
expRefresh?: number // Expiration du refresh token
}🎯 Cas d'usage
Déconnexion automatique sur expiration
userManager.watchToken((newToken) => {
if (!newToken || !userManager.isTokenValid(newToken)) {
// Token expiré ou supprimé
router.push('/login')
}
})Affichage du temps restant
setInterval(() => {
const remaining = userManager.getTokenTimeRemaining()
if (remaining !== null && remaining < 300) { // 5 minutes
showWarning(`Session expire dans ${remaining}s`)
}
}, 30000) // Vérifier toutes les 30sSynchronisation multi-onglets
// L'utilisateur se déconnecte dans l'onglet A
// → Tous les onglets B, C, D détectent le changement via watchToken
// → Redirection automatique vers /login dans tous les onglets🔧 Debug
// Afficher les informations du token
console.log('Token:', userManager.getToken())
console.log('Payload:', userManager.getDecodedToken())
console.log('Valide:', userManager.isTokenValid())
console.log('Temps restant:', userManager.getTokenTimeRemaining(), 's')
console.log('Watchers actifs:', userManager.getWatchersCount())
// Rafraîchir manuellement le cache
userManager.refreshTokenCache()📄 Changelog
Voir CHANGELOG.md
📜 Licence
Propriétaire - AMSOM Habitat
