ajout de l'authentification SSO/A5L

This commit is contained in:
2026-03-27 11:14:56 +01:00
parent f07c6c646d
commit 9fee465f81
6 changed files with 95 additions and 1 deletions

8
.theia/launch.json Normal file
View File

@@ -0,0 +1,8 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

44
public/auth.js Normal file
View File

@@ -0,0 +1,44 @@
// auth.js - Gestion de la connexion SSO
const authConfig = {
authority: "https://idp.a5l.fr/realms/A5L",
client_id: "soundboard_a5l", // À enregistrer sur votre IdP
redirect_uri: window.location.origin + "/callback.html",
response_type: "code",
scope: "openid profile email"
};
function login() {
// Construction de l'URL exacte attendue par Keycloak
const authUrl = `${authConfig.authority}/protocol/openid-connect/auth?` +
`client_id=${authConfig.client_id}&` +
`redirect_uri=${encodeURIComponent(authConfig.redirect_uri)}&` +
`response_type=${authConfig.response_type}&` +
`scope=${authConfig.scope}&` +
`state=${generateState()}`; // Sécurité recommandée
window.location.href = authUrl;
}
// Fonction utilitaire pour le paramètre 'state' (protection CSRF)
function generateState() {
const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
let result = '';
for (let i = 0; i < 16; i++) {
result += charset.charAt(Math.floor(Math.random() * charset.length));
}
return result;
}
function logout() {
localStorage.removeItem('auth_token');
window.location.reload();
}
function checkAuth() {
const token = localStorage.getItem('auth_token');
if (!token) {
document.body.classList.add('not-logged-in');
return false;
}
return true;
}

20
public/callback.html Normal file
View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<body>
<script>
// Récupération du code dans l'URL
const urlParams = new URLSearchParams(window.location.search);
const code = urlParams.get('code');
if (code) {
// Ici, normalement, on échange le code contre un token via un fetch vers l'IdP
// Pour l'exemple, on simule la réussite :
localStorage.setItem('auth_token', 'session_active_' + btoa(code));
window.location.href = 'index.html';
} else {
document.body.innerHTML = "Erreur d'authentification. Redirection...";
setTimeout(() => window.location.href = 'index.html', 2000);
}
</script>
</body>
</html>

View File

@@ -4,6 +4,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Soundboard A5L</title>
<script src="auth.js"></script>
<link rel="manifest" href="manifest.json">
<link rel="stylesheet" href="style.css">
<meta name="theme-color" content="#00f2ff">
@@ -16,9 +17,18 @@
<header>
<div style="display: flex; gap: 10px; align-items: center;">
<button class="stop-all" onclick="stopAll()">🛑 STOP ALL</button>
<span id="app-version" style="color: #555; font-size: 0.8rem; margin-left: 10px;">v1.213</span>
<span id="app-version" style="color: #555; font-size: 0.8rem; margin-left: 10px;"><a href="readme.md">1.214</a></span>
<button id="installBtn" style="display:none; ...">📥 INSTALLER</button>
<div id="auth-zone">
<button id="loginBtn" onclick="login()" style="background:var(--accent); color:black;">SE CONNECTER</button>
<div id="userProfile" style="display:none;">
<span id="userName"></span>
<button onclick="logout()" style="background:none; color:var(--danger); border:1px solid">DÉCONNEXION</button>
</div>
</div>
</div>
<button onclick="toggleEditMode()" id="toggleBtn">MODE ÉDITION</button>
</header>

View File

@@ -10,9 +10,11 @@
* Arrêt de toutes les pistes avec un bouton STOP ALL
* Progressif Web App : fonctionnement offline
* Utilisation d'IndexedDB pour stocker les son
* Empecher le device de se mettre en veille
## Fonctionnalités à venir
* Suppression d'une association
* Authentification pour stocker les sons sur le serveur
* Authentification pour récuperer les sons depuis le serveur
* Partager des sons pour que d'autres puissent les déployer dans leur soundboard

View File

@@ -43,6 +43,16 @@ async function getSound(id) {
// Lancement automatique au démarrage
// On attend que la page soit prête
window.addEventListener('load', () => {
if (checkAuth()) {
document.getElementById('loginBtn').style.display = 'none';
document.getElementById('userProfile').style.display = 'flex';
// Charger les données utilisateur depuis le serveur ici si besoin
init();
} else {
// Optionnel : afficher une grille vide ou un message
console.log("Utilisateur non connecté.");
}
migrateToIndexedDB();
});