|
|
|
@ -103,78 +103,29 @@ export class AuthService { |
|
|
|
|
* Lance la séquence de connexion initiale. |
|
|
|
|
*/ |
|
|
|
|
public runInitialLoginSequence(): Promise<void> { |
|
|
|
|
if (location.hash) { |
|
|
|
|
//console.log("Fragment de hachage rencontré, tracé sous forme de tableau...") ;
|
|
|
|
|
//console.table(location.hash.substr(1).split('&').map(kvp => kvp.split('=')));
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 0. CONFIGURATION DU CHARGEMENT:
|
|
|
|
|
// Il faut d'abord vérifier comment le serveur Keycloak est actuellement configuré:
|
|
|
|
|
return this.oauthService.loadDiscoveryDocument() |
|
|
|
|
|
|
|
|
|
// 1. HASH LOGIN:
|
|
|
|
|
// Essaye de se connecter via le fragment de hachage
|
|
|
|
|
// après avoir été redirigé depuis le serveur Keycloak depuis initImplicitFlow :
|
|
|
|
|
.then(() => this.oauthService.tryLogin()) |
|
|
|
|
|
|
|
|
|
// Charge la configuration de Keycloak et tente de se connecter
|
|
|
|
|
return this.oauthService.loadDiscoveryDocumentAndTryLogin() |
|
|
|
|
.then(() => { |
|
|
|
|
|
|
|
|
|
// Si l'acces token est valide alors tout est ok
|
|
|
|
|
if (this.oauthService.hasValidAccessToken()) { |
|
|
|
|
return Promise.resolve(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 2. SILENT LOGIN:
|
|
|
|
|
// Effectue un rafraîchissement silencieux pour le flux implicite.
|
|
|
|
|
// Utilise cette méthode pour obtenir des nouveaux tokens quand/avant que les tokens existants expirent.
|
|
|
|
|
return this.oauthService.silentRefresh() |
|
|
|
|
.then(() => Promise.resolve()) |
|
|
|
|
.catch(result => { |
|
|
|
|
// Sous-ensemble de situations de https://openid.net/specs/openid-connect-core-1_0.html#AuthError
|
|
|
|
|
// Seulement celles où il est raisonnablement certain que l'envoi de l'utilisateur au serveur Keycloak est utile.
|
|
|
|
|
const errorResponsesRequiringUserInteraction = [ |
|
|
|
|
'interaction_required', |
|
|
|
|
'login_required', |
|
|
|
|
'account_selection_required', |
|
|
|
|
'consent_required', |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
if (result |
|
|
|
|
&& result.reason |
|
|
|
|
&& errorResponsesRequiringUserInteraction.indexOf(result.reason.error) >= 0) { |
|
|
|
|
|
|
|
|
|
// 3. DEMANDE DE CONNEXION:
|
|
|
|
|
// A ce stade, nous savons avec certitude que nous devons demander à
|
|
|
|
|
// l'utilisateur de se connecter, nous le redirigeons donc vers la page de connexion.
|
|
|
|
|
|
|
|
|
|
// Activez cette option pour TOUJOURS forcer un utilisateur à se connecter.
|
|
|
|
|
this.login(); |
|
|
|
|
// Renvoie l'utilisateur vers la page de connexion
|
|
|
|
|
this.navigateToLoginPage(); |
|
|
|
|
|
|
|
|
|
// Afficher un mesage d'avertissement:
|
|
|
|
|
//console.warn("Une interaction de l'utilisateur est nécessaire pour se connecter, nous allons attendre que l'utilisateur se connecte manuellement.");
|
|
|
|
|
|
|
|
|
|
return Promise.resolve(); |
|
|
|
|
} |
|
|
|
|
//console.warn("Une interaction de l'utilisateur est nécessaire pour se connecter, l'utilisateur doit se connecter manuellement.");
|
|
|
|
|
|
|
|
|
|
return Promise.reject(result); |
|
|
|
|
}); |
|
|
|
|
return Promise.reject(); |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
.then(() => { |
|
|
|
|
// Met à jour l'observable isDoneLoadingSubject
|
|
|
|
|
// Met à jour de l'observable isDoneLoadingSubject
|
|
|
|
|
this.isDoneLoadingSubject$.next(true); |
|
|
|
|
|
|
|
|
|
// Vérifie les valeurs "undefined" et "null" pour être sûr.
|
|
|
|
|
// Notre login actuel ne devrait jamais avoir cela, mais au cas
|
|
|
|
|
// où quelqu'un appellerait la méthode initImplicitFlow(undefined|null), cela pourrait arriver.
|
|
|
|
|
if (this.oauthService.state && this.oauthService.state !== 'undefined' && this.oauthService.state !== 'null') { |
|
|
|
|
let stateUrl = this.oauthService.state; |
|
|
|
|
if (stateUrl.startsWith('/') === false) { |
|
|
|
|
stateUrl = decodeURIComponent(stateUrl); |
|
|
|
|
} |
|
|
|
|
//console.log(`Il y a eu l'état de ${this.oauthService.state}, donc nous vous envoyons à ${stateUrl}`) ;
|
|
|
|
|
this.router.navigateByUrl(stateUrl); |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
.catch(() => this.isDoneLoadingSubject$.next(true)); // Met à jour l'observable isDoneLoadingSubject
|
|
|
|
|
.catch(() => this.isDoneLoadingSubject$.next(true)); // Met à jour l'observable isDoneLoadingSubject même si il y a une erreur
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -182,9 +133,7 @@ export class AuthService { |
|
|
|
|
* @param targetUrl Url de destination |
|
|
|
|
*/ |
|
|
|
|
public login(targetUrl?: string) { |
|
|
|
|
// Note : avant la version 9.1.0 de la librairie, il fallait
|
|
|
|
|
// passer le composant encodageURIC dans les arguments de la méthode.
|
|
|
|
|
this.oauthService.initLoginFlow(targetUrl || this.router.url); |
|
|
|
|
this.oauthService.initCodeFlow(targetUrl || this.router.url); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -207,7 +156,7 @@ export class AuthService { |
|
|
|
|
*/ |
|
|
|
|
public get firstRole() { |
|
|
|
|
if(this.identityClaims != null) |
|
|
|
|
return this.oauthService.getIdentityClaims()['roles'][0];
|
|
|
|
|
return this.identityClaims['roles'][0];
|
|
|
|
|
else |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
@ -217,7 +166,7 @@ export class AuthService { |
|
|
|
|
*/ |
|
|
|
|
public get roles() {
|
|
|
|
|
if(this.identityClaims != null) |
|
|
|
|
return this.oauthService.getIdentityClaims()['roles'];
|
|
|
|
|
return this.identityClaims['roles'];
|
|
|
|
|
else |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
@ -227,14 +176,14 @@ export class AuthService { |
|
|
|
|
*/ |
|
|
|
|
public get userInfo() {
|
|
|
|
|
if(this.identityClaims != null) |
|
|
|
|
return this.oauthService.getIdentityClaims()['name'];
|
|
|
|
|
return this.identityClaims['name'];
|
|
|
|
|
else |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Normalement, un service comme celui-ci ne les expose pas,
|
|
|
|
|
// mais pour le débogage, c'est logique.
|
|
|
|
|
// Normalement, ce genre de service ne les expose pas,
|
|
|
|
|
// mais pour le débogage, ça peut-être utile.
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Access_token actuel. |
|
|
|
|