221 lines
6.7 KiB
TypeScript
221 lines
6.7 KiB
TypeScript
![]() |
import { Injectable } from '@angular/core';
|
||
|
|
||
|
export type CognitoAuthProvider = 'amplify' | 'oidc';
|
||
|
|
||
|
export interface CognitoAuthConfig {
|
||
|
provider: CognitoAuthProvider;
|
||
|
region: string;
|
||
|
userPoolId: string;
|
||
|
userPoolWebClientId: string;
|
||
|
domain: string;
|
||
|
redirectSignIn: string;
|
||
|
redirectSignOut: string;
|
||
|
scopes: string[];
|
||
|
requireAuth?: boolean;
|
||
|
}
|
||
|
|
||
|
interface AuthProviderApi {
|
||
|
initialize(configuration: CognitoAuthConfig): Promise<void>;
|
||
|
signIn(): Promise<void>;
|
||
|
signOut(): Promise<void>;
|
||
|
isAuthenticated(): Promise<boolean>;
|
||
|
getIdToken(): Promise<string | null>;
|
||
|
getAccessToken(): Promise<string | null>;
|
||
|
handleCallback(): Promise<void>;
|
||
|
}
|
||
|
|
||
|
@Injectable({ providedIn: 'root' })
|
||
|
export class CognitoAuthService implements AuthProviderApi {
|
||
|
private configuration: CognitoAuthConfig | null = null;
|
||
|
private activeProvider: CognitoAuthProvider | null = null;
|
||
|
|
||
|
async initialize(configuration: CognitoAuthConfig): Promise<void> {
|
||
|
this.configuration = configuration;
|
||
|
this.activeProvider = configuration.provider;
|
||
|
|
||
|
if (configuration.provider === 'amplify') {
|
||
|
const { Amplify } = await import('aws-amplify');
|
||
|
Amplify.configure({
|
||
|
Auth: {
|
||
|
region: configuration.region,
|
||
|
userPoolId: configuration.userPoolId,
|
||
|
userPoolWebClientId: configuration.userPoolWebClientId,
|
||
|
oauth: {
|
||
|
domain: configuration.domain,
|
||
|
scope: configuration.scopes,
|
||
|
redirectSignIn: configuration.redirectSignIn,
|
||
|
redirectSignOut: configuration.redirectSignOut,
|
||
|
responseType: 'code'
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (configuration.provider === 'oidc') {
|
||
|
// Configuration du provider OIDC via angular-oauth2-oidc.
|
||
|
// On s'attend à ce que l'app configure OAuthService au bootstrap
|
||
|
// (loadDiscoveryDocumentAndLogin, etc.). Ici, rien à faire si ce n'est valider la présence.
|
||
|
const { OAuthService } = await import('angular-oauth2-oidc');
|
||
|
const injector = (window as any).ngInjector;
|
||
|
if (!injector) {
|
||
|
throw new Error('Injector Angular global introuvable. Exposez window.ngInjector au bootstrap.');
|
||
|
}
|
||
|
const oauthService = injector.get(OAuthService);
|
||
|
if (!oauthService) {
|
||
|
throw new Error('OAuthService non disponible. Vérifiez l\'installation et la configuration angular-oauth2-oidc.');
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
throw new Error('Provider non pris en charge. Utilisez "amplify" ou "oidc".');
|
||
|
}
|
||
|
|
||
|
async signIn(): Promise<void> {
|
||
|
this.assertInitialized();
|
||
|
if (this.activeProvider === 'amplify') {
|
||
|
const { Auth } = await import('aws-amplify');
|
||
|
await Auth.federatedSignIn();
|
||
|
return;
|
||
|
}
|
||
|
if (this.activeProvider === 'oidc') {
|
||
|
const { OAuthService } = await import('angular-oauth2-oidc');
|
||
|
const injector = (window as any).ngInjector;
|
||
|
const oauthService = injector.get(OAuthService);
|
||
|
oauthService.initLoginFlow();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async signOut(): Promise<void> {
|
||
|
this.assertInitialized();
|
||
|
if (this.activeProvider === 'amplify') {
|
||
|
const { Auth } = await import('aws-amplify');
|
||
|
await Auth.signOut();
|
||
|
return;
|
||
|
}
|
||
|
if (this.activeProvider === 'oidc') {
|
||
|
const { OAuthService } = await import('angular-oauth2-oidc');
|
||
|
const injector = (window as any).ngInjector;
|
||
|
const oauthService = injector.get(OAuthService);
|
||
|
oauthService.logOut();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async isAuthenticated(): Promise<boolean> {
|
||
|
this.assertInitialized();
|
||
|
if (this.activeProvider === 'amplify') {
|
||
|
try {
|
||
|
const { Auth } = await import('aws-amplify');
|
||
|
const session = await Auth.currentSession();
|
||
|
return !!session?.getIdToken()?.getJwtToken();
|
||
|
} catch {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.activeProvider === 'oidc') {
|
||
|
try {
|
||
|
const { OAuthService } = await import('angular-oauth2-oidc');
|
||
|
const injector = (window as any).ngInjector;
|
||
|
const oauthService = injector.get(OAuthService);
|
||
|
return oauthService.hasValidAccessToken() || oauthService.hasValidIdToken();
|
||
|
} catch {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
async getIdToken(): Promise<string | null> {
|
||
|
this.assertInitialized();
|
||
|
if (this.activeProvider === 'amplify') {
|
||
|
try {
|
||
|
const { Auth } = await import('aws-amplify');
|
||
|
const session = await Auth.currentSession();
|
||
|
return session.getIdToken().getJwtToken() ?? null;
|
||
|
} catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.activeProvider === 'oidc') {
|
||
|
try {
|
||
|
const { OAuthService } = await import('angular-oauth2-oidc');
|
||
|
const injector = (window as any).ngInjector;
|
||
|
const oauthService = injector.get(OAuthService);
|
||
|
return oauthService.getIdToken() ?? null;
|
||
|
} catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
async getAccessToken(): Promise<string | null> {
|
||
|
this.assertInitialized();
|
||
|
if (this.activeProvider === 'amplify') {
|
||
|
try {
|
||
|
const { Auth } = await import('aws-amplify');
|
||
|
const session = await Auth.currentSession();
|
||
|
return session.getAccessToken().getJwtToken() ?? null;
|
||
|
} catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.activeProvider === 'oidc') {
|
||
|
try {
|
||
|
const { OAuthService } = await import('angular-oauth2-oidc');
|
||
|
const injector = (window as any).ngInjector;
|
||
|
const oauthService = injector.get(OAuthService);
|
||
|
return oauthService.getAccessToken() ?? null;
|
||
|
} catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
async handleCallback(): Promise<void> {
|
||
|
this.assertInitialized();
|
||
|
if (this.activeProvider === 'amplify') {
|
||
|
// Amplify gère l'échange code->tokens automatiquement lors du retour.
|
||
|
// Appeler currentSession() force la résolution de la session.
|
||
|
const { Auth } = await import('aws-amplify');
|
||
|
await Auth.currentSession();
|
||
|
return;
|
||
|
}
|
||
|
if (this.activeProvider === 'oidc') {
|
||
|
// Pour angular-oauth2-oidc, la prise en charge est faite au bootstrap avec
|
||
|
// loadDiscoveryDocumentAndLogin(). Rien à faire ici si c'est déjà configuré.
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async ensureAuthenticated(loginRoute: string): Promise<boolean> {
|
||
|
const isAuthed = await this.isAuthenticated();
|
||
|
if (isAuthed) {
|
||
|
return true;
|
||
|
}
|
||
|
if (this.configuration?.requireAuth) {
|
||
|
// Redirection douce vers la page de login Angular
|
||
|
window.location.assign(loginRoute);
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private assertInitialized(): void {
|
||
|
if (!this.configuration || !this.activeProvider) {
|
||
|
throw new Error('CognitoAuthService non initialisé. Appelez initialize(config).');
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|