keycloak improve with build 2
This commit is contained in:
parent
246051b4f4
commit
7a8b736241
@ -1,13 +1,48 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { signIn, useSession } from "next-auth/react";
|
import { signIn, useSession } from "next-auth/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useRef } from "react";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
export default function SignIn() {
|
export default function SignIn() {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
const [initializationStatus, setInitializationStatus] = useState<string | null>(null);
|
const [initializationStatus, setInitializationStatus] = useState<string | null>(null);
|
||||||
|
const hasAttemptedLogin = useRef(false);
|
||||||
|
const isLogoutRedirect = useRef(false);
|
||||||
|
|
||||||
|
// Check if this is a logout redirect (from Keycloak post_logout_redirect_uri)
|
||||||
|
useEffect(() => {
|
||||||
|
// Check URL parameters or session storage for logout flag
|
||||||
|
const logoutParam = searchParams.get('logout');
|
||||||
|
const fromLogout = sessionStorage.getItem('just_logged_out');
|
||||||
|
|
||||||
|
if (logoutParam === 'true' || fromLogout === 'true') {
|
||||||
|
isLogoutRedirect.current = true;
|
||||||
|
sessionStorage.removeItem('just_logged_out');
|
||||||
|
|
||||||
|
// Clear any OAuth parameters from URL to prevent callback processing
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const hasOAuthParams = url.searchParams.has('code') ||
|
||||||
|
url.searchParams.has('state') ||
|
||||||
|
url.searchParams.has('error');
|
||||||
|
|
||||||
|
if (hasOAuthParams) {
|
||||||
|
// Remove OAuth parameters but keep logout=true
|
||||||
|
url.searchParams.delete('code');
|
||||||
|
url.searchParams.delete('state');
|
||||||
|
url.searchParams.delete('error');
|
||||||
|
url.searchParams.delete('error_description');
|
||||||
|
url.searchParams.set('logout', 'true');
|
||||||
|
// Replace URL without OAuth params
|
||||||
|
window.history.replaceState({}, '', url.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't auto-trigger login after logout
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}, [searchParams]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// If user is already authenticated, redirect to home
|
// If user is already authenticated, redirect to home
|
||||||
@ -16,10 +51,30 @@ export default function SignIn() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only trigger Keycloak sign-in if not authenticated and not loading
|
// Don't auto-login if this is a logout redirect or we've already attempted login
|
||||||
|
if (isLogoutRedirect.current || hasAttemptedLogin.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't auto-login if status is still loading (might be processing OAuth callback)
|
||||||
|
if (status === "loading") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only trigger Keycloak sign-in if not authenticated, not loading, and not from logout
|
||||||
|
// Add a longer delay to ensure OAuth callbacks have completed
|
||||||
if (status === "unauthenticated") {
|
if (status === "unauthenticated") {
|
||||||
// Trigger Keycloak sign-in
|
hasAttemptedLogin.current = true;
|
||||||
signIn("keycloak", { callbackUrl: "/" });
|
// Longer delay to ensure we're not in a logout redirect flow or OAuth callback
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
// Double-check we're still unauthenticated and not in a logout flow
|
||||||
|
if (!isLogoutRedirect.current) {
|
||||||
|
// Trigger Keycloak sign-in
|
||||||
|
signIn("keycloak", { callbackUrl: "/" });
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
}
|
}
|
||||||
}, [status, session, router]);
|
}, [status, session, router]);
|
||||||
|
|
||||||
@ -57,6 +112,9 @@ export default function SignIn() {
|
|||||||
}
|
}
|
||||||
}, [session]);
|
}, [session]);
|
||||||
|
|
||||||
|
// Show logout message if coming from logout
|
||||||
|
const showLogoutMessage = isLogoutRedirect.current || searchParams.get('logout') === 'true';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="min-h-screen flex items-center justify-center"
|
className="min-h-screen flex items-center justify-center"
|
||||||
@ -70,7 +128,9 @@ export default function SignIn() {
|
|||||||
<div className="w-full max-w-md space-y-8 bg-white/90 backdrop-blur-sm p-8 rounded-xl shadow-xl">
|
<div className="w-full max-w-md space-y-8 bg-white/90 backdrop-blur-sm p-8 rounded-xl shadow-xl">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">
|
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">
|
||||||
{initializationStatus === "initializing"
|
{showLogoutMessage
|
||||||
|
? "Vous avez été déconnecté avec succès"
|
||||||
|
: initializationStatus === "initializing"
|
||||||
? "Initialisation de votre espace..."
|
? "Initialisation de votre espace..."
|
||||||
: initializationStatus === "success"
|
: initializationStatus === "success"
|
||||||
? "Initialisation réussie, redirection..."
|
? "Initialisation réussie, redirection..."
|
||||||
@ -78,6 +138,20 @@ export default function SignIn() {
|
|||||||
? "Échec de l'initialisation. Veuillez réessayer."
|
? "Échec de l'initialisation. Veuillez réessayer."
|
||||||
: "Redirection vers la page de connexion..."}
|
: "Redirection vers la page de connexion..."}
|
||||||
</h2>
|
</h2>
|
||||||
|
{showLogoutMessage && (
|
||||||
|
<div className="mt-4 text-center">
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
hasAttemptedLogin.current = false;
|
||||||
|
isLogoutRedirect.current = false;
|
||||||
|
signIn("keycloak", { callbackUrl: "/" });
|
||||||
|
}}
|
||||||
|
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
|
||||||
|
>
|
||||||
|
Se connecter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{initializationStatus === "initializing" && (
|
{initializationStatus === "initializing" && (
|
||||||
<div className="flex justify-center mt-4">
|
<div className="flex justify-center mt-4">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
|
||||||
|
|||||||
@ -10,13 +10,16 @@ export function SignOutHandler() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleSignOut = async () => {
|
const handleSignOut = async () => {
|
||||||
try {
|
try {
|
||||||
|
// Mark that we're logging out to prevent auto-login
|
||||||
|
sessionStorage.setItem('just_logged_out', 'true');
|
||||||
|
|
||||||
// Get Keycloak issuer from environment
|
// Get Keycloak issuer from environment
|
||||||
const keycloakIssuer = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER;
|
const keycloakIssuer = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER;
|
||||||
const idToken = session?.idToken;
|
const idToken = session?.idToken;
|
||||||
|
|
||||||
// First, sign out from NextAuth (clears NextAuth cookies)
|
// First, sign out from NextAuth (clears NextAuth cookies)
|
||||||
await signOut({
|
await signOut({
|
||||||
callbackUrl: "/signin",
|
callbackUrl: "/signin?logout=true",
|
||||||
redirect: false
|
redirect: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -29,10 +32,10 @@ export function SignOutHandler() {
|
|||||||
`${keycloakIssuer}/protocol/openid-connect/logout`
|
`${keycloakIssuer}/protocol/openid-connect/logout`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add required parameters
|
// Add required parameters - include logout=true in redirect URI
|
||||||
keycloakLogoutUrl.searchParams.append(
|
keycloakLogoutUrl.searchParams.append(
|
||||||
'post_logout_redirect_uri',
|
'post_logout_redirect_uri',
|
||||||
window.location.origin + '/signin'
|
window.location.origin + '/signin?logout=true'
|
||||||
);
|
);
|
||||||
keycloakLogoutUrl.searchParams.append(
|
keycloakLogoutUrl.searchParams.append(
|
||||||
'id_token_hint',
|
'id_token_hint',
|
||||||
@ -43,12 +46,12 @@ export function SignOutHandler() {
|
|||||||
window.location.href = keycloakLogoutUrl.toString();
|
window.location.href = keycloakLogoutUrl.toString();
|
||||||
} else {
|
} else {
|
||||||
// Fallback: just redirect to signin if we don't have Keycloak info
|
// Fallback: just redirect to signin if we don't have Keycloak info
|
||||||
window.location.href = '/signin';
|
window.location.href = '/signin?logout=true';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error during sign out:', error);
|
console.error('Error during sign out:', error);
|
||||||
// Fallback: redirect to signin on error
|
// Fallback: redirect to signin on error
|
||||||
window.location.href = '/signin';
|
window.location.href = '/signin?logout=true';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -362,12 +362,15 @@ export function MainNav() {
|
|||||||
className="text-white/80 hover:text-white hover:bg-black/50 cursor-pointer"
|
className="text-white/80 hover:text-white hover:bg-black/50 cursor-pointer"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
|
// Mark that we're logging out to prevent auto-login
|
||||||
|
sessionStorage.setItem('just_logged_out', 'true');
|
||||||
|
|
||||||
const keycloakIssuer = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER;
|
const keycloakIssuer = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER;
|
||||||
const idToken = session?.idToken;
|
const idToken = session?.idToken;
|
||||||
|
|
||||||
// First sign out from NextAuth (clears NextAuth cookies)
|
// First sign out from NextAuth (clears NextAuth cookies)
|
||||||
await signOut({
|
await signOut({
|
||||||
callbackUrl: '/signin',
|
callbackUrl: '/signin?logout=true',
|
||||||
redirect: false
|
redirect: false
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -377,10 +380,10 @@ export function MainNav() {
|
|||||||
`${keycloakIssuer}/protocol/openid-connect/logout`
|
`${keycloakIssuer}/protocol/openid-connect/logout`
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add required parameters
|
// Add required parameters - include logout=true in redirect URI
|
||||||
keycloakLogoutUrl.searchParams.append(
|
keycloakLogoutUrl.searchParams.append(
|
||||||
'post_logout_redirect_uri',
|
'post_logout_redirect_uri',
|
||||||
window.location.origin + '/signin'
|
window.location.origin + '/signin?logout=true'
|
||||||
);
|
);
|
||||||
keycloakLogoutUrl.searchParams.append(
|
keycloakLogoutUrl.searchParams.append(
|
||||||
'id_token_hint',
|
'id_token_hint',
|
||||||
@ -391,12 +394,12 @@ export function MainNav() {
|
|||||||
window.location.href = keycloakLogoutUrl.toString();
|
window.location.href = keycloakLogoutUrl.toString();
|
||||||
} else {
|
} else {
|
||||||
// Fallback: just redirect to signin if we don't have Keycloak info
|
// Fallback: just redirect to signin if we don't have Keycloak info
|
||||||
window.location.href = '/signin';
|
window.location.href = '/signin?logout=true';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error during logout:', error);
|
console.error('Error during logout:', error);
|
||||||
// Fallback to simple redirect if something goes wrong
|
// Fallback to simple redirect if something goes wrong
|
||||||
window.location.href = '/signin';
|
window.location.href = '/signin?logout=true';
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user