diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0193641 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +KEYCLOAK_DB_NAME=keycloak +KEYCLOAK_DB_USER=keycloak +KEYCLOAK_DB_PASSWORD=change-me +KEYCLOAK_ADMIN_USER=admin +KEYCLOAK_ADMIN_PASSWORD=change-me diff --git a/.gitignore b/.gitignore index aa605ff..d78b62a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .codex +.env WhatsApp Video 2026-04-11 at 20.38.50.mp4 ChessCubing.App/bin/ ChessCubing.App/obj/ diff --git a/ChessCubing.App/App.razor b/ChessCubing.App/App.razor index 983d151..5bdf683 100644 --- a/ChessCubing.App/App.razor +++ b/ChessCubing.App/App.razor @@ -1,5 +1,20 @@ - - - - - + + + + + + + + Authentification + Verification de la session en cours... + + + + + + + + + + + diff --git a/ChessCubing.App/ChessCubing.App.csproj b/ChessCubing.App/ChessCubing.App.csproj index dbbd2f6..883d2b4 100644 --- a/ChessCubing.App/ChessCubing.App.csproj +++ b/ChessCubing.App/ChessCubing.App.csproj @@ -11,6 +11,7 @@ + diff --git a/ChessCubing.App/Components/RedirectToLogin.razor b/ChessCubing.App/Components/RedirectToLogin.razor new file mode 100644 index 0000000..4cb94b6 --- /dev/null +++ b/ChessCubing.App/Components/RedirectToLogin.razor @@ -0,0 +1,13 @@ +@inject NavigationManager Navigation + +@code { + protected override void OnInitialized() + { + var relativePath = Navigation.ToBaseRelativePath(Navigation.Uri); + var returnUrl = string.IsNullOrWhiteSpace(relativePath) + ? "/" + : relativePath.StartsWith("/", StringComparison.Ordinal) ? relativePath : $"/{relativePath}"; + + Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(returnUrl)}"); + } +} diff --git a/ChessCubing.App/Components/UserAccessBar.razor b/ChessCubing.App/Components/UserAccessBar.razor new file mode 100644 index 0000000..f75a4ec --- /dev/null +++ b/ChessCubing.App/Components/UserAccessBar.razor @@ -0,0 +1,85 @@ +@using System.Security.Claims +@inject NavigationManager Navigation + + + + + + Compte Keycloak + @BuildDisplayName(authState.User) + @BuildMeta(authState.User) + + + Se deconnecter + + + + + + + Compte Keycloak + Connexion requise pour lancer et reprendre les matchs + Chaque compte conserve son propre etat de match dans ce navigateur. + + + Se connecter + + + + + +@code { + private string LoginHref => BuildAuthHref("login", CurrentReturnUrl); + private string LogoutHref => BuildAuthHref("logout", "/"); + + private string CurrentReturnUrl + { + get + { + var relativePath = Navigation.ToBaseRelativePath(Navigation.Uri); + if (string.IsNullOrWhiteSpace(relativePath)) + { + return "/"; + } + + return relativePath.StartsWith("/", StringComparison.Ordinal) + ? relativePath + : $"/{relativePath}"; + } + } + + private static string BuildAuthHref(string action, string returnUrl) + => $"authentication/{action}?returnUrl={Uri.EscapeDataString(returnUrl)}"; + + private static string BuildDisplayName(ClaimsPrincipal user) + => user.Identity?.Name + ?? user.FindFirst("name")?.Value + ?? user.FindFirst("preferred_username")?.Value + ?? "Utilisateur connecte"; + + private static string BuildMeta(ClaimsPrincipal user) + { + var details = new List(); + var email = user.FindFirst("email")?.Value; + if (!string.IsNullOrWhiteSpace(email)) + { + details.Add(email); + } + + var roles = user.FindAll("role") + .Select(claim => claim.Value) + .Where(value => !string.IsNullOrWhiteSpace(value)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(value => value, StringComparer.OrdinalIgnoreCase) + .ToArray(); + + if (roles.Length > 0) + { + details.Add($"Roles : {string.Join(", ", roles)}"); + } + + return details.Count > 0 + ? string.Join(" | ", details) + : "Session authentifiee via Keycloak."; + } +} diff --git a/ChessCubing.App/Pages/ApplicationPage.razor b/ChessCubing.App/Pages/ApplicationPage.razor index b8e469f..4b20a23 100644 --- a/ChessCubing.App/Pages/ApplicationPage.razor +++ b/ChessCubing.App/Pages/ApplicationPage.razor @@ -1,5 +1,6 @@ @page "/application" @page "/application.html" +@attribute [Authorize] @inject BrowserBridge Browser @inject MatchStore Store @inject NavigationManager Navigation @@ -23,6 +24,7 @@ Accueil du site Consulter le reglement +
Authentification