Can someone help me with this issue? I am trying to retrieve the role using get role(): string
but it's not returning the full role name. For example, instead of getting "Head Administrator", I only get "Administrator" returned. I know that Role["Administrator"]
would work, but the problem lies in IUser.role
being of type Role | undefined
, which complicates the situation and prevents me from simply using
get role(): string {
return Role[this.authService.userInfo?.role];
}
so that is not an option.
header.component.ts
import { Component } from '@angular/core';
import { AuthService } from '@core/services';
import { LayoutComponent } from '../layout.component';
@Component({
selector: 'app-header',
templateUrl: './header.component.html'
})
export class HeaderComponent {
get username(): string {
return this.authService.userInfo?.username || '';
}
get role(): string {
return this.authService.userInfo?.role || '';
}
constructor(private authService: AuthService, public app: LayoutComponent) {}
signOut(event: any) {
this.authService.signOut();
event.preventDefault();
}
}
user.model.ts
export interface IUser extends IEntity {
email: string;
username: string;
role: Role;
}
export enum Role {
Administrator = 'Head Administrator',
DepartmentAdministrator = 'Department Administrator',
User = 'Super User'
}
auth.service.ts
import { Injectable, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
import { delay, map, tap } from 'rxjs/operators';
import { environment } from '@env';
import { IAuthResponse, IUser } from '@core/models';
import { INITIAL_AUTH_STATE } from '@core/constants';
import { JwtService } from '../util';
@Injectable({
providedIn: 'root'
})
export class AuthService implements OnDestroy {
private readonly TOKEN_URL = `${environment.apiUrl}/Accounts/token`;
private currentUserSubject = new BehaviorSubject<IAuthResponse>(INITIAL_AUTH_STATE);
private timer!: Subscription;
currentUser$: Observable<IAuthResponse> = this.currentUserSubject.asObservable();
get userInfo(): IUser | null {
const accessToken = this.currentUserValue?.accessToken;
return accessToken ? this.jwtService.decodeToken<IUser>(accessToken) : null;
}
private get currentUserValue(): IAuthResponse | null {
return this.currentUserSubject.value;
}
private get localStorageCurrentUser(): IAuthResponse {
const localStorageUser = localStorage.getItem('currentUser');
return localStorageUser ? JSON.parse(localStorageUser) : INITIAL_AUTH_STATE;
}
constructor(
private httpClient: HttpClient,
private router: Router,
private jwtService: JwtService
) {
this.currentUserSubject.next(this.localStorageCurrentUser);
window.addEventListener('storage', this.storageEventListener.bind(this));
}
ngOnDestroy(): void {
window.removeEventListener('storage', this.storageEventListener.bind(this));
}
signIn(username: string, password: string): Observable<IAuthResponse> {
const TOKEN_URL: string = this.TOKEN_URL + '/create';
return this.httpClient
.post<IAuthResponse>(TOKEN_URL, {
username,
password
})
.pipe(
map((res) => {
if (res && res.accessToken) {
this.setCurrentUser(res);
}
return res;
})
);
}
signOut(): void {
this.clearCurrentUser();
this.router.navigate(['auth']);
}
refreshToken(): Observable<IAuthResponse | null> {
const refreshToken = this.currentUserValue?.refreshToken;
if (!refreshToken) {
this.clearCurrentUser();
return of(null);
}
return this.httpClient.post<IAuthResponse>(`${this.TOKEN_URL}/refresh`, { refreshToken }).pipe(
map((res) => {
this.setCurrentUser(res);
return res;
})
);
}
private setCurrentUser(user: IAuthResponse): void {
this.currentUserSubject.next(user);
this.setLocalStorage(user);
this.startTokenTimer();
}
private clearCurrentUser(): void {
this.currentUserSubject.next(INITIAL_AUTH_STATE);
this.clearLocalStorage();
this.stopTokenTimer();
}
private setLocalStorage(userState: IAuthResponse): void {
localStorage.setItem('currentUser', JSON.stringify(userState));
localStorage.setItem('login-event', 'login' + Math.random());
}
private clearLocalStorage(): void {
localStorage.removeItem('currentUser');
localStorage.setItem('logout-event', 'logout' + Math.random());
}
private getTokenRemainingTime(): number {
const expiresAtUtc = this.currentUserValue?.expiresAtUtc;
if (!expiresAtUtc) {
return 0;
}
const expires = new Date(expiresAtUtc);
return expires.getTime() - Date.now();
}
private startTokenTimer(): void {
const timeout = this.getTokenRemainingTime();
this.timer = of(true)
.pipe(
delay(timeout),
tap(() => this.refreshToken().subscribe())
)
.subscribe();
}
private stopTokenTimer(): void {
this.timer?.unsubscribe();
}
private storageEventListener(event: StorageEvent): void {
if (event.storageArea === localStorage) {
if (event.key === 'logout-event') {
this.currentUserSubject.next(INITIAL_AUTH_STATE);
}
if (event.key === 'login-event') {
location.reload();
}
}
}
}