waiting for initialization
This commit is contained in:
parent
7fdc87fb0b
commit
d6768b3da9
|
|
@ -5,11 +5,14 @@ import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@a
|
||||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||||
import { KeycloakService } from 'keycloak-angular';
|
import { KeycloakService } from 'keycloak-angular';
|
||||||
import { environment } from '../environments/environment';
|
import { environment } from '../environments/environment';
|
||||||
|
import { customKeycloakAdapter } from '../keycloak';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { LoadingInterceptor } from './interceptors/loading.interceptor';
|
import { LoadingInterceptor } from './interceptors/loading.interceptor';
|
||||||
import { KeycloakInitializerService } from './services/keycloak-initializer.service';
|
import { KeycloakInitializerService } from './services/keycloak-initializer.service';
|
||||||
import { SelectOptionsService } from './services/select-options.service';
|
import { SelectOptionsService } from './services/select-options.service';
|
||||||
|
import { createLogger } from './utils/utils';
|
||||||
// provideClientHydration()
|
// provideClientHydration()
|
||||||
|
const logger = createLogger('ApplicationConfig');
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
provideHttpClient(withInterceptorsFromDi()),
|
provideHttpClient(withInterceptorsFromDi()),
|
||||||
|
|
@ -17,7 +20,8 @@ export const appConfig: ApplicationConfig = {
|
||||||
{
|
{
|
||||||
provide: APP_INITIALIZER,
|
provide: APP_INITIALIZER,
|
||||||
// useFactory: initializeKeycloak,
|
// useFactory: initializeKeycloak,
|
||||||
useFactory: (keycloakInitializer: KeycloakInitializerService) => async () => await keycloakInitializer.initialize(),
|
//useFactory: initializeKeycloak,
|
||||||
|
useFactory: initializeKeycloak3,
|
||||||
multi: true,
|
multi: true,
|
||||||
//deps: [KeycloakService],
|
//deps: [KeycloakService],
|
||||||
deps: [KeycloakInitializerService],
|
deps: [KeycloakInitializerService],
|
||||||
|
|
@ -49,9 +53,32 @@ function initServices(selectOptions: SelectOptionsService) {
|
||||||
await selectOptions.init();
|
await selectOptions.init();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
export function initializeKeycloak3(keycloak: KeycloakInitializerService) {
|
||||||
|
return () => keycloak.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function initializeKeycloak2(keycloak: KeycloakService): () => Promise<void> {
|
||||||
|
return async () => {
|
||||||
|
const { url, realm, clientId } = environment.keycloak;
|
||||||
|
const adapter = customKeycloakAdapter(() => keycloak.getKeycloakInstance(), {});
|
||||||
|
if (window.location.search.length > 0) {
|
||||||
|
sessionStorage.setItem('SEARCH', window.location.search);
|
||||||
|
}
|
||||||
|
const { host, hostname, href, origin, pathname, port, protocol, search } = window.location;
|
||||||
|
await keycloak.init({
|
||||||
|
config: { url, realm, clientId },
|
||||||
|
initOptions: {
|
||||||
|
onLoad: 'check-sso',
|
||||||
|
silentCheckSsoRedirectUri: window.location.hostname === 'localhost' ? `${window.location.origin}/assets/silent-check-sso.html` : `${window.location.origin}/dealerweb/assets/silent-check-sso.html`,
|
||||||
|
adapter,
|
||||||
|
redirectUri: `${origin}${pathname}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
function initializeKeycloak(keycloak: KeycloakService) {
|
function initializeKeycloak(keycloak: KeycloakService) {
|
||||||
return async () => {
|
return async () => {
|
||||||
|
logger.info(`###>calling keycloakService init ...`);
|
||||||
const authenticated = await keycloak.init({
|
const authenticated = await keycloak.init({
|
||||||
config: {
|
config: {
|
||||||
url: environment.keycloak.url,
|
url: environment.keycloak.url,
|
||||||
|
|
@ -63,6 +90,6 @@ function initializeKeycloak(keycloak: KeycloakService) {
|
||||||
silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
console.log(`--->${authenticated}`);
|
logger.info(`+++>${authenticated}`);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Router, UrlTree } from '@angular/router';
|
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||||
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';
|
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';
|
||||||
import { KeycloakInitializerService } from '../services/keycloak-initializer.service';
|
import { KeycloakInitializerService } from '../services/keycloak-initializer.service';
|
||||||
|
import { createLogger } from '../utils/utils';
|
||||||
|
const logger = createLogger('AuthGuard');
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
|
|
@ -11,14 +12,30 @@ export class AuthGuard extends KeycloakAuthGuard {
|
||||||
super(router, keycloak);
|
super(router, keycloak);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isAccessAllowed(): Promise<boolean | UrlTree> {
|
async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean | UrlTree> {
|
||||||
if (!this.keycloakInitializer.isInitialized()) {
|
logger.info(`--->AuthGuard`);
|
||||||
await this.keycloakInitializer.initialize();
|
while (!this.keycloakInitializer.initialized) {
|
||||||
|
logger.info(`Waiting 100 msec`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
}
|
}
|
||||||
|
// Force the user to log in if currently unauthenticated.
|
||||||
const authenticated = this.keycloak.isLoggedIn();
|
const authenticated = this.keycloak.isLoggedIn();
|
||||||
if (!authenticated) {
|
if (!this.authenticated && !authenticated) {
|
||||||
await this.router.navigate(['/home']);
|
await this.keycloak.login({
|
||||||
|
redirectUri: window.location.origin + state.url,
|
||||||
|
});
|
||||||
|
// return false;
|
||||||
}
|
}
|
||||||
return authenticated;
|
|
||||||
|
// Get the roles required from the route.
|
||||||
|
const requiredRoles = route.data['roles'];
|
||||||
|
|
||||||
|
// Allow the user to proceed if no additional roles are required to access the route.
|
||||||
|
if (!Array.isArray(requiredRoles) || requiredRoles.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow the user to proceed if all the required roles are present.
|
||||||
|
return requiredRoles.every(role => this.roles.includes(role));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,14 @@ import { createLogger } from '../utils/utils';
|
||||||
const logger = createLogger('KeycloakInitializerService');
|
const logger = createLogger('KeycloakInitializerService');
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class KeycloakInitializerService {
|
export class KeycloakInitializerService {
|
||||||
private initialized = false;
|
public initialized = false;
|
||||||
|
|
||||||
constructor(private keycloakService: KeycloakService) {}
|
constructor(private keycloakService: KeycloakService) {}
|
||||||
|
|
||||||
async initialize(): Promise<void> {
|
async initialize(): Promise<boolean> {
|
||||||
if (this.initialized) {
|
return new Promise<boolean>(async (resolve, reject) => {
|
||||||
return;
|
try {
|
||||||
}
|
await this.keycloakService.init({
|
||||||
|
|
||||||
const authenticated = await this.keycloakService.init({
|
|
||||||
config: {
|
config: {
|
||||||
url: environment.keycloak.url,
|
url: environment.keycloak.url,
|
||||||
realm: environment.keycloak.realm,
|
realm: environment.keycloak.realm,
|
||||||
|
|
@ -23,21 +21,44 @@ export class KeycloakInitializerService {
|
||||||
initOptions: {
|
initOptions: {
|
||||||
onLoad: 'check-sso',
|
onLoad: 'check-sso',
|
||||||
silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
||||||
flow: 'implicit',
|
// flow: 'implicit',
|
||||||
},
|
},
|
||||||
// initOptions: {
|
|
||||||
// pkceMethod: 'S256',
|
|
||||||
// redirectUri: environment.keycloak.redirectUri,
|
|
||||||
// checkLoginIframe: false,
|
|
||||||
// },
|
|
||||||
});
|
});
|
||||||
const token = await this.keycloakService.getToken();
|
|
||||||
logger.info(`--->${authenticated}:${token}`);
|
|
||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
|
resolve(true);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// if (this.initialized) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// logger.info(`###>calling keycloakService init ...`);
|
||||||
|
// const authenticated = await this.keycloakService.init({
|
||||||
|
// config: {
|
||||||
|
// url: environment.keycloak.url,
|
||||||
|
// realm: environment.keycloak.realm,
|
||||||
|
// clientId: environment.keycloak.clientId,
|
||||||
|
// },
|
||||||
|
// initOptions: {
|
||||||
|
// onLoad: 'check-sso',
|
||||||
|
// silentCheckSsoRedirectUri: (<any>window).location.origin + '/assets/silent-check-sso.html',
|
||||||
|
// // flow: 'implicit',
|
||||||
|
// },
|
||||||
|
// // initOptions: {
|
||||||
|
// // pkceMethod: 'S256',
|
||||||
|
// // redirectUri: environment.keycloak.redirectUri,
|
||||||
|
// // checkLoginIframe: false,
|
||||||
|
// // },
|
||||||
|
// });
|
||||||
|
// logger.info(`+++>authenticated: ${authenticated}`);
|
||||||
|
// const token = await this.keycloakService.getToken();
|
||||||
|
// logger.info(`--->${token}`);
|
||||||
|
|
||||||
|
// this.initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
isInitialized(): boolean {
|
// isInitialized(): boolean {
|
||||||
return this.initialized;
|
// return this.initialized;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { KeycloakAdapter, KeycloakInstance, KeycloakLoginOptions, KeycloakLogoutOptions, KeycloakRegisterOptions } from 'keycloak-js';
|
||||||
|
import { createLogger } from './app/utils/utils';
|
||||||
|
|
||||||
|
const logger = createLogger('keycloak');
|
||||||
|
export type OptionsOrProvider<T> = Partial<T> | (() => Partial<T>);
|
||||||
|
/**
|
||||||
|
* Create and immediately resolve a KeycloakPromise
|
||||||
|
*/
|
||||||
|
const createPromise = () => new Promise<void>(resolve => resolve());
|
||||||
|
/**
|
||||||
|
* Resolve OptionsOrProvider: if it's an function, execute it, otherwise return it.
|
||||||
|
*/
|
||||||
|
const resolveOptions = <T>(opt: OptionsOrProvider<T>): Partial<T> => (typeof opt === 'function' ? opt() : opt);
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Update options with the overrides given as OptionsOrProvider
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
* @param overrides
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const updateOptions = <T>(options: T, overrides: OptionsOrProvider<T>): T => Object.assign(options ?? <T>{}, resolveOptions(overrides));
|
||||||
|
/**
|
||||||
|
* Keycloak adapter that supports options customization.
|
||||||
|
*
|
||||||
|
* All options can either be given as lazily evaluated provider functions (that will be evaluated
|
||||||
|
* right before navigating) or eagerly evaluated objects. These options will have precedence
|
||||||
|
* over options passed by keycloak-js.
|
||||||
|
*
|
||||||
|
* Cf. https://www.keycloak.org/docs/15.0/securing_apps/#custom-adapters
|
||||||
|
*
|
||||||
|
* Actual implementation copied more or less verbatim from
|
||||||
|
* https://github.com/keycloak/keycloak-js-bower/blob/10.0.2/dist/keycloak.js#L1136
|
||||||
|
*
|
||||||
|
* @param kc Function that returns a Keycloak instance
|
||||||
|
* @param loginOptions login options
|
||||||
|
* @param logoutOptions logout options
|
||||||
|
* @param registerOptions register options
|
||||||
|
* @returns KeycloakAdapter
|
||||||
|
*/
|
||||||
|
export function customKeycloakAdapter(
|
||||||
|
kc: () => KeycloakInstance,
|
||||||
|
loginOptions: OptionsOrProvider<KeycloakLoginOptions> = {},
|
||||||
|
logoutOptions: OptionsOrProvider<KeycloakLogoutOptions> = {},
|
||||||
|
registerOptions: OptionsOrProvider<KeycloakRegisterOptions> = {},
|
||||||
|
): KeycloakAdapter {
|
||||||
|
return {
|
||||||
|
login: (options?: KeycloakLoginOptions): Promise<void> => {
|
||||||
|
updateOptions(options, loginOptions);
|
||||||
|
logger.info('Executing login. Options: ', options);
|
||||||
|
window.location.replace(kc().createLoginUrl(options));
|
||||||
|
return createPromise();
|
||||||
|
},
|
||||||
|
logout: (options?: KeycloakLogoutOptions): Promise<void> => {
|
||||||
|
updateOptions(options, logoutOptions);
|
||||||
|
logger.info('Executing logout. Options: ', options);
|
||||||
|
window.location.replace(kc().createLogoutUrl(options));
|
||||||
|
return createPromise();
|
||||||
|
},
|
||||||
|
register: (options?: KeycloakRegisterOptions): Promise<void> => {
|
||||||
|
updateOptions(options, registerOptions);
|
||||||
|
logger.info('Executing register. Options: ', options);
|
||||||
|
window.location.replace(kc().createRegisterUrl(options));
|
||||||
|
return createPromise();
|
||||||
|
},
|
||||||
|
accountManagement: (): Promise<void> => {
|
||||||
|
const accountUrl = kc().createAccountUrl();
|
||||||
|
logger.info('Executing account management');
|
||||||
|
if (typeof accountUrl !== 'undefined') {
|
||||||
|
window.location.href = accountUrl;
|
||||||
|
} else {
|
||||||
|
throw new Error('Not supported by the OIDC server');
|
||||||
|
}
|
||||||
|
return createPromise();
|
||||||
|
},
|
||||||
|
redirectUri: (options: { redirectUri: string }) => {
|
||||||
|
if (options?.redirectUri) {
|
||||||
|
return options.redirectUri;
|
||||||
|
}
|
||||||
|
if (kc().redirectUri) {
|
||||||
|
return kc().redirectUri;
|
||||||
|
}
|
||||||
|
return window.location.href;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue