connexion avec o365

This commit is contained in:
2025-08-12 16:14:44 +02:00
parent 871f166457
commit e1e4e81420
5 changed files with 119 additions and 7 deletions

View File

@@ -8,6 +8,8 @@
"name": "gestion-conges-jsx", "name": "gestion-conges-jsx",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@azure/msal-browser": "^4.19.0",
"@azure/msal-react": "^3.0.17",
"lucide-react": "^0.344.0", "lucide-react": "^0.344.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
@@ -46,6 +48,40 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@azure/msal-browser": {
"version": "4.19.0",
"resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.19.0.tgz",
"integrity": "sha512-g6Ea+sJmK7l5NUyrPhtD7DNj/tZcsr6VTNNLNuYs8yPvL3HNiIpO/0kzXntF9AqJ/6L+uz9aHmoT1x+RNq6zBQ==",
"license": "MIT",
"dependencies": {
"@azure/msal-common": "15.10.0"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-common": {
"version": "15.10.0",
"resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.10.0.tgz",
"integrity": "sha512-+cGnma71NV3jzl6DdgdHsqriN4ZA7puBIzObSYCvcIVGMULGb2NrcOGV6IJxO06HoVRHFKijkxd9lcBvS063KQ==",
"license": "MIT",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@azure/msal-react": {
"version": "3.0.17",
"resolved": "https://registry.npmjs.org/@azure/msal-react/-/msal-react-3.0.17.tgz",
"integrity": "sha512-GgVn8OQmtXMPJ88+w8E+7hpWXcVWhh8aIjspkrJr4bbONWhbfyQOSyN92gsrSbynIsJ9o7GWTjvGHFLr2MuyQQ==",
"license": "MIT",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@azure/msal-browser": "^4.19.0",
"react": "^16.8.0 || ^17 || ^18 || ^19"
}
},
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.25.7", "version": "7.25.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz",

View File

@@ -9,6 +9,8 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@azure/msal-browser": "^4.19.0",
"@azure/msal-react": "^3.0.17",
"lucide-react": "^0.344.0", "lucide-react": "^0.344.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",

12
project/src/AuthConfig.js Normal file
View File

@@ -0,0 +1,12 @@
// authConfig.js
export const msalConfig = {
auth: {
clientId: "4bb4cc24-bac3-427c-b02c-5d14fc67b561", // Application (client) ID dans Azure
authority: "https://login.microsoftonline.com/9840a2a0-6ae1-4688-b03d-d2ec291be0f9", // Directory (tenant) ID
redirectUri: "http://localhost:5173"
}
};
export const loginRequest = {
scopes: ["User.Read"] // Permet de lire le profil utilisateur
};

View File

@@ -1,4 +1,5 @@
import React, { createContext, useContext, useState, useEffect } from 'react'; import React, { createContext, useContext, useState, useEffect } from 'react';
import * as msal from '@azure/msal-browser';
const AuthContext = createContext(); const AuthContext = createContext();
@@ -10,11 +11,32 @@ export const useAuth = () => {
return context; return context;
}; };
const msalConfig = {
auth: {
clientId: '4bb4cc24-bac3-427c-b02c-5d14fc67b561',
authority: 'https://login.microsoftonline.com/9840a2a0-6ae1-4688-b03d-d2ec291be0f9',
redirectUri: window.location.origin,
},
};
const msalInstance = new msal.PublicClientApplication(msalConfig);
export const AuthProvider = ({ children }) => { export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
// Initialise MSAL au montage
useEffect(() => { useEffect(() => {
const initializeMsal = async () => {
try {
await msalInstance.initialize();
} catch (error) {
console.error("Erreur d'initialisation MSAL:", error);
}
};
initializeMsal();
const savedUser = localStorage.getItem('user'); const savedUser = localStorage.getItem('user');
if (savedUser) { if (savedUser) {
try { try {
@@ -88,12 +110,37 @@ export const AuthProvider = ({ children }) => {
} }
}; };
const loginWithO365 = async () => {
try {
const loginResponse = await msalInstance.loginPopup({
scopes: ["user.read"]
});
const account = loginResponse.account;
if (account) {
const userData = {
id: account.homeAccountId,
name: account.name,
email: account.username,
role: 'Employe',
service: 'Non défini',
};
setUser(userData);
localStorage.setItem('user', JSON.stringify(userData));
return true;
}
return false;
} catch (error) {
console.error('Erreur login Office 365:', error);
return false;
}
};
const logout = () => { const logout = () => {
setUser(null); setUser(null);
localStorage.removeItem('user'); localStorage.removeItem('user');
}; };
const value = { user, login, logout, isLoading }; const value = { user, login, loginWithO365, logout, isLoading };
return ( return (
<AuthContext.Provider value={value}> <AuthContext.Provider value={value}>

View File

@@ -9,8 +9,9 @@ const Login = () => {
const [showPassword, setShowPassword] = useState(false); const [showPassword, setShowPassword] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(''); const [error, setError] = useState('');
const { login } = useAuth();
const navigate = useNavigate(); const navigate = useNavigate();
const { login, loginWithO365 } = useAuth();
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
e.preventDefault(); e.preventDefault();
@@ -33,8 +34,6 @@ const Login = () => {
<div className="h-32 lg:h-auto lg:flex lg:w-1/2 bg-cover bg-center" <div className="h-32 lg:h-auto lg:flex lg:w-1/2 bg-cover bg-center"
style={{ backgroundImage: "url('/assets/ImageEnsup.png')" }}> style={{ backgroundImage: "url('/assets/ImageEnsup.png')" }}>
<div className="w-full bg-black bg-opacity-40 flex items-center justify-center p-4"> <div className="w-full bg-black bg-opacity-40 flex items-center justify-center p-4">
</div> </div>
</div> </div>
@@ -92,12 +91,28 @@ const Login = () => {
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-900" className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500 hover:text-gray-900"
title={showPassword ? "Masquer le mot de passe" : "Afficher le mot de passe"} title={showPassword ? "Masquer le mot de passe" : "Afficher le mot de passe"}
> >
{/* L'icône est choisie en fonction de l'état de showPassword */} {showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
</button> </button>
</div> </div>
</div> </div>
<div className="mt-6 text-center">
<button
onClick={async () => {
const success = await loginWithO365();
if (success) {
navigate('/dashboard');
} else {
setError("Erreur lors de la connexion Office 365");
}
}}
type="button"
className="w-full bg-gray-700 text-white py-3 rounded-lg font-medium hover:bg-green-700 transition-colors"
>
Se connecter avec Office 365
</button>
</div>
{error && ( {error && (
<div className="p-2 lg:p-3 bg-red-50 border border-red-200 rounded-lg"> <div className="p-2 lg:p-3 bg-red-50 border border-red-200 rounded-lg">
<p className="text-red-600 text-xs lg:text-sm">{error}</p> <p className="text-red-600 text-xs lg:text-sm">{error}</p>
@@ -119,4 +134,4 @@ const Login = () => {
); );
}; };
export default Login; export default Login;