Files
GTA/project/src/context/AuthContext.jsx
2025-12-03 11:02:33 +01:00

300 lines
11 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { createContext, useContext, useState, useEffect } from 'react';
import * as msal from '@azure/msal-browser';
// ✅ Correction: Import de API_BASE_URL
import { msalConfig, loginRequest, API_BASE_URL } from '../authConfig';
const AuthContext = createContext();
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) throw new Error('useAuth must be used within an AuthProvider');
return context;
};
const msalInstance = new msal.PublicClientApplication(msalConfig);
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [userGroups, setUserGroups] = useState([]);
const [isAuthorized, setIsAuthorized] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [isMsalInitialized, setIsMsalInitialized] = useState(false);
// ✅ Fonction corrigée pour construire l'URL
const getApiUrl = (endpoint) => {
const cleanEndpoint = endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
// API_BASE_URL est "/api", donc cela retourne "/api/endpoint"
return `${API_BASE_URL}/${cleanEndpoint}`;
};
// --- Vérifie l'autorisation de l'utilisateur via groupes
const checkUserAuthorization = async (userPrincipalName, accessToken) => {
try {
const response = await fetch(getApiUrl('check-user-groups'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
body: JSON.stringify({ userPrincipalName })
});
if (response.ok) {
const data = await response.json();
setUserGroups(data.groups || []);
setIsAuthorized(data.authorized || false);
return data;
}
return { authorized: false, groups: [] };
} catch (error) {
console.error('Erreur vérification groupes:', error);
return { authorized: false, groups: [] };
}
};
// --- Synchronisation utilisateur connecté
const syncUserToDatabase = async (entraUser, accessToken) => {
try {
const response = await fetch(getApiUrl('initial-sync'), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`
},
body: JSON.stringify(entraUser)
});
if (response.ok) {
const data = await response.json();
console.log('Utilisateur synchronisé:', entraUser.userPrincipalName);
return data;
}
} catch (error) {
console.error('Erreur synchronisation utilisateur:', error);
}
return null;
};
// --- Full sync admin
const fullSyncDatabase = async (accessToken) => {
try {
const response = await fetch(getApiUrl('initial-sync'), {
method: 'POST',
headers: { 'Authorization': `Bearer ${accessToken}` }
});
if (response.ok) {
const data = await response.json();
console.log('Full sync terminée:', data);
return data;
}
} catch (error) {
console.error('Erreur full sync:', error);
}
return null;
};
// --- S'assurer que MSAL est initialisé avant tout appel
const ensureMsalInitialized = async () => {
if (!isMsalInitialized) {
try {
await msalInstance.initialize();
setIsMsalInitialized(true);
console.log('MSAL initialisé');
} catch (error) {
console.error('Erreur initialisation MSAL:', error);
throw error;
}
}
};
// --- Initialisation au chargement
useEffect(() => {
const initializeMsal = async () => {
try {
await ensureMsalInitialized();
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
try {
const response = await msalInstance.acquireTokenSilent({
...loginRequest,
account: accounts[0]
});
await handleSuccessfulAuth(response);
} catch (error) {
console.log('Token silent acquisition failed:', error);
}
}
} catch (error) {
console.error("Erreur d'initialisation MSAL:", error);
} finally {
setIsLoading(false);
}
};
initializeMsal();
}, []);
// --- Gestion login réussi
const handleSuccessfulAuth = async (authResponse) => {
try {
const account = authResponse.account;
const accessToken = authResponse.accessToken;
let entraUser = {
id: account.homeAccountId,
displayName: account.name,
userPrincipalName: account.username,
mail: account.username
};
const graphResponse = await fetch('https://graph.microsoft.com/v1.0/me', {
headers: { 'Authorization': `Bearer ${accessToken}` }
});
if (graphResponse.ok) {
const graphData = await graphResponse.json();
entraUser = { ...entraUser, ...graphData };
}
// 1⃣ Synchroniser lutilisateur connecté
const syncResult = await syncUserToDatabase(entraUser, accessToken);
// 2⃣ Full sync si admin
if (syncResult?.role === 'Admin') {
console.log('Admin détecté → lancement full sync...');
await fullSyncDatabase(accessToken);
}
// 3⃣ Vérifier groupes
const authResult = await checkUserAuthorization(entraUser.userPrincipalName, accessToken);
if (authResult.authorized) {
setUser({
id: syncResult?.localUserId || entraUser.id,
CollaborateurADId: syncResult?.localUserId,
entraUserId: entraUser.id,
name: entraUser.displayName,
prenom: entraUser.givenName || entraUser.displayName?.split(' ')[0] || '',
nom: entraUser.surname || entraUser.displayName?.split(' ')[1] || '',
email: entraUser.mail || entraUser.userPrincipalName,
userPrincipalName: entraUser.userPrincipalName,
role: syncResult?.role || 'Employe',
service: syncResult?.service || entraUser.department || 'Non défini',
jobTitle: entraUser.jobTitle,
department: entraUser.department,
officeLocation: entraUser.officeLocation,
typeContrat: syncResult?.typeContrat || '37h',
dateEntree: syncResult?.dateEntree || null,
groups: authResult.groups
});
setIsAuthorized(true);
} else {
throw new Error('Utilisateur non autorisé - pas membre des groupes requis');
}
} catch (error) {
console.error('Erreur lors de la gestion de l\'authentification:', error);
throw error;
}
};
// --- Connexion classique
const login = async (email, password) => {
try {
const response = await fetch(getApiUrl('login'), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, mot_de_passe: password })
});
if (!response.ok) throw new Error('Erreur de connexion');
const data = await response.json();
if (data.success) {
setUser({
id: data.user.id,
name: `${data.user.prenom} ${data.user.nom}`,
prenom: data.user.prenom,
nom: data.user.nom,
email: data.user.email,
role: data.user.role || 'Employe',
service: data.user.service || 'Non défini'
});
setIsAuthorized(true);
return true;
}
return false;
} catch (error) {
console.error("Erreur de connexion:", error);
return false;
}
};
// --- Connexion Office 365
const loginWithO365 = async () => {
try {
await ensureMsalInitialized();
const authResponse = await msalInstance.loginPopup(loginRequest);
await handleSuccessfulAuth(authResponse);
return true;
} catch (error) {
console.error('Erreur login Office 365:', error);
if (error.message?.includes('non autorisé')) {
throw new Error('Accès refusé: Vous n\'êtes pas membre d\'un groupe autorisé.');
}
throw error;
}
};
// --- Déconnexion
const logout = async () => {
try {
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
await msalInstance.logoutPopup({ account: accounts[0] });
}
} catch (error) {
console.error('Erreur lors de la déconnexion:', error);
} finally {
setUser(null);
setUserGroups([]);
setIsAuthorized(false);
}
};
// --- Obtenir token API
const getAccessToken = async () => {
try {
await ensureMsalInitialized();
const accounts = msalInstance.getAllAccounts();
if (accounts.length === 0) throw new Error('Aucun compte connecté');
const response = await msalInstance.acquireTokenSilent({
...loginRequest,
account: accounts[0]
});
return response.accessToken;
} catch (error) {
console.error('Erreur obtention token:', error);
return null;
}
};
const value = {
user,
userGroups,
isAuthorized,
login,
loginWithO365,
logout,
isLoading,
getAccessToken
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
export default AuthContext;