keycloack funcionando
This commit is contained in:
parent
01b93eca37
commit
c84c9a95c8
@ -1,5 +1,5 @@
|
||||
{
|
||||
"realm": "angular-app",
|
||||
"realm": "aangular-app",
|
||||
"auth-server-url": "http://localhost:8080/",
|
||||
"resource": "angular-app",
|
||||
"credentials": {
|
||||
|
||||
@ -35,34 +35,42 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Authentication success handling
|
||||
if (event.type === KeycloakEventType.AuthSuccess) {
|
||||
console.log('Authentication successful, redirecting to home');
|
||||
this.router.navigate(['/inicio']);
|
||||
console.log('Authentication successful');
|
||||
// We'll let the guards and login component handle redirections
|
||||
// No redirect here to avoid conflicts
|
||||
}
|
||||
|
||||
// Authentication error handling
|
||||
if (event.type === KeycloakEventType.AuthError) {
|
||||
console.error('Authentication error, redirecting to login');
|
||||
this.router.navigate(['/login']);
|
||||
console.error('Authentication error');
|
||||
// Only redirect to login if not already there
|
||||
if (this.router.url !== '/login') {
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
}
|
||||
|
||||
// Logout handling
|
||||
if (event.type === KeycloakEventType.AuthLogout) {
|
||||
console.log('Logged out, redirecting to login');
|
||||
this.router.navigate(['/login']);
|
||||
console.log('Logged out');
|
||||
// Only redirect to login if not already there
|
||||
if (this.router.url !== '/login') {
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
// Subscribe to navigation events
|
||||
this.router.events
|
||||
.pipe(
|
||||
filter(event => event instanceof NavigationEnd),
|
||||
takeUntilDestroyed()
|
||||
)
|
||||
.subscribe(() => {
|
||||
console.log('Navigation completed to:', this.router.url);
|
||||
});
|
||||
// Subscribe to navigation events - using standard unsubscribe pattern
|
||||
this.subscriptions.push(
|
||||
this.router.events
|
||||
.pipe(
|
||||
filter(event => event instanceof NavigationEnd)
|
||||
)
|
||||
.subscribe(() => {
|
||||
console.log('Navigation completed to:', this.router.url);
|
||||
})
|
||||
);
|
||||
|
||||
// Check authentication status on load
|
||||
this.checkAuthenticationStatus();
|
||||
@ -78,25 +86,20 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
const isLoggedIn = await this.keycloak.authenticated;
|
||||
console.log('Initial authentication status:', isLoggedIn ? 'Authenticated' : 'Not authenticated');
|
||||
|
||||
if (isLoggedIn) {
|
||||
// Already authenticated, check if on protected route
|
||||
if (this.router.url === '/login') {
|
||||
this.router.navigate(['/inicio']);
|
||||
}
|
||||
} else {
|
||||
// Not authenticated but trying to access a protected route
|
||||
const isPublicRoute = this.router.url === '/login';
|
||||
|
||||
if (!isPublicRoute) {
|
||||
console.log('User not authenticated, redirecting to Keycloak login');
|
||||
// Store current URL for redirect after login
|
||||
const currentUrl = this.router.url;
|
||||
|
||||
// Start Keycloak login flow
|
||||
this.keycloak.login({
|
||||
redirectUri: window.location.origin + currentUrl
|
||||
});
|
||||
}
|
||||
// Let the guards handle the protected routes
|
||||
// Only do minimal checks here to avoid redirect loops
|
||||
|
||||
// If the user is on login page but already authenticated, send to home
|
||||
if (isLoggedIn && this.router.url === '/login') {
|
||||
console.log('Already authenticated, redirecting from login to home');
|
||||
this.router.navigate(['/inicio']);
|
||||
return;
|
||||
}
|
||||
|
||||
// If not authenticated and on a protected route, go to Keycloak login
|
||||
if (!isLoggedIn && this.router.url !== '/login') {
|
||||
// We'll let the auth guard handle this
|
||||
console.log('Not authenticated on protected route');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking authentication status:', error);
|
||||
|
||||
@ -51,15 +51,16 @@ export const appConfig: ApplicationConfig = {
|
||||
// Provide Keycloak with initOptions - this automatically creates an APP_INITIALIZER
|
||||
provideKeycloak({
|
||||
config: {
|
||||
url: 'http://localhost:8080',
|
||||
realm: 'angular-app',
|
||||
clientId: 'angular-app'
|
||||
url: 'http://localhost:8080', // Asegúrate de que esta URL coincida con tu servidor Keycloak
|
||||
realm: 'angular-app', // Asegúrate de que este realm existe en tu servidor Keycloak
|
||||
clientId: 'angular-app',
|
||||
},
|
||||
initOptions: {
|
||||
onLoad: 'check-sso',
|
||||
onLoad: 'check-sso', // Cambiado de check-sso a login-required para forzar login
|
||||
silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
|
||||
checkLoginIframe: false,
|
||||
pkceMethod: 'S256' // Added for better security
|
||||
pkceMethod: 'S256',
|
||||
enableLogging: true
|
||||
},
|
||||
// Configure the interceptor by providing the URLs where to include the token
|
||||
providers: [
|
||||
|
||||
@ -4,7 +4,7 @@ import Keycloak from 'keycloak-js';
|
||||
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
import { createAuthGuard, AuthGuardData } from 'keycloak-angular';
|
||||
|
||||
// This is a simplified direct implementation
|
||||
// Simple implementation for authentication guard
|
||||
export const authGuard: CanActivateFn = async (
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
@ -12,28 +12,24 @@ export const authGuard: CanActivateFn = async (
|
||||
const keycloak = inject(Keycloak);
|
||||
const router = inject(Router);
|
||||
|
||||
// Check if user is authenticated
|
||||
const authenticated = await keycloak.authenticated;
|
||||
|
||||
if (authenticated) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not authenticated, redirect to Keycloak login
|
||||
console.log('User not authenticated, redirecting to Keycloak login');
|
||||
|
||||
// Store the URL the user was trying to access
|
||||
const returnUrl = state.url;
|
||||
|
||||
try {
|
||||
await keycloak.login({
|
||||
redirectUri: window.location.origin + returnUrl
|
||||
// Check if user is authenticated
|
||||
const authenticated = await keycloak.authenticated;
|
||||
|
||||
if (authenticated) {
|
||||
console.log('User is authenticated, allowing access to protected route');
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not authenticated, redirect to login
|
||||
console.log('User not authenticated, redirecting to login page');
|
||||
return router.createUrlTree(['/login'], {
|
||||
queryParams: { returnUrl: state.url !== '/' ? state.url : '/inicio' }
|
||||
});
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error('Error during login redirect:', error);
|
||||
// Fallback to local login component if Keycloak login fails
|
||||
return router.createUrlTree(['/login'], { queryParams: { returnUrl } });
|
||||
console.error('Error checking authentication:', error);
|
||||
// Fallback to login on error
|
||||
return router.createUrlTree(['/login']);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -12,6 +12,8 @@ import { ToastModule } from 'primeng/toast';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { FooterComponent } from "../../components/footer/footer.component";
|
||||
import { AuthService } from '../../services/auth.service';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
@ -43,16 +45,22 @@ export class LoginComponent implements OnInit {
|
||||
|
||||
constructor(private messageService: MessageService) {}
|
||||
|
||||
async ngOnInit() {
|
||||
ngOnInit() {
|
||||
// Obtener el returnUrl de los query params si existe
|
||||
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/inicio';
|
||||
|
||||
// Verificar si ya está autenticado y redirigir
|
||||
this.authService.isLoggedIn().subscribe(isLoggedIn => {
|
||||
if (isLoggedIn) {
|
||||
console.log('Usuario ya autenticado, redirigiendo...');
|
||||
this.router.navigateByUrl(this.returnUrl);
|
||||
}
|
||||
// Simplificación - verificar autenticación sin promesas anidadas
|
||||
this.authService.isLoggedIn().subscribe({
|
||||
next: (isLoggedIn) => {
|
||||
if (isLoggedIn) {
|
||||
console.log('Usuario ya autenticado, redirigiendo a:', this.returnUrl);
|
||||
// Verificar si la URL de retorno es válida
|
||||
const effectiveReturnUrl = this.returnUrl === '/' ? '/inicio' : this.returnUrl;
|
||||
// Redirigir
|
||||
this.router.navigate([effectiveReturnUrl], { replaceUrl: true });
|
||||
}
|
||||
},
|
||||
error: (error) => console.error('Error al verificar autenticación:', error)
|
||||
});
|
||||
}
|
||||
|
||||
@ -61,12 +69,16 @@ export class LoginComponent implements OnInit {
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
// Construir el redirectUri para que vuelva a la URL que estaba intentando acceder
|
||||
const redirectUri = window.location.origin + this.returnUrl;
|
||||
// Verificar si la URL de retorno es válida
|
||||
const effectiveReturnUrl = this.returnUrl === '/' ? '/inicio' : this.returnUrl;
|
||||
|
||||
// Construir el redirectUri
|
||||
const redirectUri = window.location.origin + effectiveReturnUrl;
|
||||
console.log('Iniciando login con redirectUri:', redirectUri);
|
||||
|
||||
// Iniciar el flujo de autenticación de Keycloak
|
||||
await this.authService.login(redirectUri);
|
||||
// No es necesario manejar el redirect aquí, Keycloak lo hará automáticamente
|
||||
// Keycloak se encargará de la redirección
|
||||
} catch (error) {
|
||||
console.error('Error al iniciar sesión:', error);
|
||||
this.loading = false;
|
||||
|
||||
@ -4,7 +4,7 @@ import { BehaviorSubject, Observable, from } from 'rxjs';
|
||||
import { KEYCLOAK_EVENT_SIGNAL, KeycloakEventType } from 'keycloak-angular';
|
||||
import { Router } from '@angular/router';
|
||||
import Keycloak from 'keycloak-js';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { MessageService } from 'primeng/api';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -14,6 +14,7 @@ export class AuthService {
|
||||
private keycloak = inject(Keycloak);
|
||||
private keycloakEvents = inject(KEYCLOAK_EVENT_SIGNAL);
|
||||
private router = inject(Router);
|
||||
private messageService = inject(MessageService);
|
||||
|
||||
// User state
|
||||
private userSubject = new BehaviorSubject<any>(null);
|
||||
@ -22,6 +23,9 @@ export class AuthService {
|
||||
// Authentication state as a signal
|
||||
public isAuthenticated = signal<boolean>(false);
|
||||
|
||||
// Login error state
|
||||
public loginError = signal<string | null>(null);
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
// Check initial state
|
||||
this.checkInitialAuthState();
|
||||
@ -36,6 +40,7 @@ export class AuthService {
|
||||
// On successful login
|
||||
if (event.type === KeycloakEventType.AuthSuccess) {
|
||||
this.isAuthenticated.set(true);
|
||||
this.loginError.set(null);
|
||||
this.loadUserInfo();
|
||||
}
|
||||
|
||||
@ -51,6 +56,16 @@ export class AuthService {
|
||||
console.error('Authentication error:', event);
|
||||
this.isAuthenticated.set(false);
|
||||
this.userSubject.next(null);
|
||||
|
||||
// Mostrar mensaje de error
|
||||
const errorMsg = 'Error de autenticación. Por favor, verifica tus credenciales o inténtalo más tarde.';
|
||||
this.loginError.set(errorMsg);
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Error de autenticación',
|
||||
detail: errorMsg,
|
||||
life: 5000
|
||||
});
|
||||
}
|
||||
|
||||
// On token expiration
|
||||
@ -72,6 +87,14 @@ export class AuthService {
|
||||
} catch (error) {
|
||||
console.error('Error checking initial auth state:', error);
|
||||
this.isAuthenticated.set(false);
|
||||
|
||||
// Mostrar mensaje de error
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'No se pudo verificar el estado de autenticación.',
|
||||
life: 5000
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,27 +131,73 @@ export class AuthService {
|
||||
} catch (error) {
|
||||
console.error('Error loading user profile:', error);
|
||||
this.userSubject.next(null);
|
||||
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'No se pudo cargar la información del usuario.',
|
||||
life: 5000
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
login(redirectUri?: string): Promise<void> {
|
||||
return this.keycloak.login({
|
||||
redirectUri: redirectUri || window.location.origin
|
||||
});
|
||||
async login(redirectUri?: string): Promise<void> {
|
||||
try {
|
||||
this.loginError.set(null);
|
||||
await this.keycloak.login({
|
||||
redirectUri: redirectUri || window.location.origin
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Login error:', error);
|
||||
this.loginError.set('Error al iniciar sesión. Por favor, inténtalo de nuevo.');
|
||||
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Error de inicio de sesión',
|
||||
detail: 'No se pudo iniciar sesión. Por favor, inténtalo de nuevo.',
|
||||
life: 5000
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
logout(): Promise<void> {
|
||||
return this.keycloak.logout({
|
||||
redirectUri: window.location.origin
|
||||
});
|
||||
async logout(): Promise<void> {
|
||||
try {
|
||||
await this.keycloak.logout({
|
||||
redirectUri: window.location.origin
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Logout error:', error);
|
||||
// Intento manual de navegar a login en caso de error
|
||||
this.router.navigate(['/login']);
|
||||
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Error al cerrar sesión.',
|
||||
life: 5000
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isLoggedIn(): Observable<boolean> {
|
||||
return from(Promise.resolve(this.keycloak.authenticated));
|
||||
try {
|
||||
// Usar directamente la propiedad authenticated de Keycloak
|
||||
return from(Promise.resolve(this.keycloak.authenticated || false));
|
||||
} catch (error) {
|
||||
console.error('Error al verificar autenticación:', error);
|
||||
return from(Promise.resolve(false));
|
||||
}
|
||||
}
|
||||
|
||||
getToken(): Promise<string> {
|
||||
return Promise.resolve(this.keycloak.token || '');
|
||||
try {
|
||||
return Promise.resolve(this.keycloak.token || '');
|
||||
} catch (error) {
|
||||
console.error('Error al obtener token:', error);
|
||||
return Promise.resolve('');
|
||||
}
|
||||
}
|
||||
|
||||
async updateToken(minValidity = 30): Promise<boolean> {
|
||||
@ -136,7 +205,16 @@ export class AuthService {
|
||||
return await this.keycloak.updateToken(minValidity);
|
||||
} catch (error) {
|
||||
console.error('Error refreshing token:', error);
|
||||
await this.login();
|
||||
// No redireccionar automáticamente al login, mostrar mensaje primero
|
||||
this.messageService.add({
|
||||
severity: 'warn',
|
||||
summary: 'Sesión expirada',
|
||||
detail: 'Tu sesión ha expirado. Por favor, inicia sesión nuevamente.',
|
||||
life: 5000
|
||||
});
|
||||
|
||||
// Esperar un momento para que el usuario vea el mensaje
|
||||
setTimeout(() => this.login(), 2000);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user