import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { HttpClient } from '@angular/common/http'; import { Observable, ReplaySubject, of } from 'rxjs'; import { shareReplay, tap, catchError } from 'rxjs/operators'; import { StateStorageService } from 'app/core/auth/state-storage.service'; import { ApplicationConfigService } from '../config/application-config.service'; import { Account } from 'app/core/auth/account.model'; @Injectable({ providedIn: 'root' }) export class AccountService { private userIdentity: Account | null = null; private authenticationState = new ReplaySubject(1); private accountCache$?: Observable | null; constructor( private http: HttpClient, private stateStorageService: StateStorageService, private router: Router, private applicationConfigService: ApplicationConfigService ) {} authenticate(identity: Account | null): void { this.userIdentity = identity; this.authenticationState.next(this.userIdentity); if (!identity) { this.accountCache$ = null; } } hasAnyAuthority(authorities: string[] | string): boolean { if (!this.userIdentity) { return false; } if (!Array.isArray(authorities)) { authorities = [authorities]; } return this.userIdentity.authorities.some((authority: string) => authorities.includes(authority)); } identity(force?: boolean): Observable { if (!this.accountCache$ || force) { this.accountCache$ = this.fetch().pipe( tap((account: Account) => { this.authenticate(account); this.navigateToStoredUrl(); }), shareReplay() ); } return this.accountCache$.pipe(catchError(() => of(null))); } isAuthenticated(): boolean { return this.userIdentity !== null; } getAuthenticationState(): Observable { return this.authenticationState.asObservable(); } private fetch(): Observable { return this.http.get(this.applicationConfigService.getEndpointFor('api/account')); } private navigateToStoredUrl(): void { // previousState can be set in the authExpiredInterceptor and in the userRouteAccessService // if login is successful, go to stored previousState and clear previousState const previousUrl = this.stateStorageService.getUrl(); if (previousUrl) { this.stateStorageService.clearUrl(); this.router.navigateByUrl(previousUrl); } } }