147 lines
3.9 KiB
TypeScript
147 lines
3.9 KiB
TypeScript
import {Injectable, signal} from '@angular/core';
|
|
import {LoginService} from '@api';
|
|
import {BehaviorSubject, Observable, throwError} from 'rxjs';
|
|
import {catchError, tap} from 'rxjs/operators';
|
|
import {MatSnackBar} from '@angular/material/snack-bar';
|
|
import {JwtHelperService} from '@auth0/angular-jwt';
|
|
import {JwtClaims} from '@custom-types/jwt_interface'
|
|
import {environment} from '@environment';
|
|
|
|
@Injectable({
|
|
providedIn: 'root'
|
|
})
|
|
export class AuthService {
|
|
private isAuthenticatedSubject = new BehaviorSubject<boolean>(environment.defaultAuthStatus);
|
|
public isAuthenticated$ = this.isAuthenticatedSubject.asObservable();
|
|
|
|
private userClaimsSubject = new BehaviorSubject<JwtClaims | null>(null);
|
|
public userClaims$ = this.userClaimsSubject.asObservable();
|
|
private jwtHelper = new JwtHelperService();
|
|
private _username = signal<string | null>(environment.defaultAuthStatus ? 'akastijn' : null);
|
|
public readonly username = this._username.asReadonly();
|
|
|
|
constructor(
|
|
private loginService: LoginService,
|
|
private snackBar: MatSnackBar
|
|
) {
|
|
// Check if user is already logged in on service initialization
|
|
this.checkAuthStatus();
|
|
}
|
|
|
|
/**
|
|
* Attempt to login with the provided code
|
|
*/
|
|
public login(code: string): Observable<any> {
|
|
return this.loginService.login(code).pipe(
|
|
tap(jwt => {
|
|
this.saveJwt(jwt);
|
|
this.isAuthenticatedSubject.next(true);
|
|
|
|
this.reloadUsername();
|
|
}),
|
|
catchError(error => {
|
|
this.snackBar.open('Login failed', '', {duration: 2000});
|
|
return throwError(() => error);
|
|
})
|
|
);
|
|
}
|
|
|
|
private reloadUsername() {
|
|
this.loginService.getUsername().pipe(
|
|
tap(username => {
|
|
this._username.set(username.username);
|
|
}),
|
|
catchError(error => {
|
|
return throwError(() => error);
|
|
})
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Log the user out by removing the JWT
|
|
*/
|
|
public logout(): void {
|
|
localStorage.removeItem('jwt');
|
|
this.isAuthenticatedSubject.next(false);
|
|
this.userClaimsSubject.next(null);
|
|
this._username.set(null);
|
|
}
|
|
|
|
/**
|
|
* Check if the user is authenticated
|
|
*/
|
|
public checkAuthStatus(): boolean {
|
|
const jwt = this.getJwt();
|
|
if (!jwt) {
|
|
console.log("No JWT found");
|
|
return false;
|
|
}
|
|
try {
|
|
if (this.jwtHelper.isTokenExpired(jwt)) {
|
|
this.logout();
|
|
console.log("Token expired, logging out");
|
|
return false;
|
|
}
|
|
|
|
const claims = this.extractJwtClaims(jwt);
|
|
console.log("User claims: ", claims);
|
|
this.userClaimsSubject.next(claims);
|
|
this.isAuthenticatedSubject.next(true);
|
|
this.reloadUsername();
|
|
return true;
|
|
} catch (e) {
|
|
this.logout();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get the JWT from localStorage
|
|
*/
|
|
public getJwt(): string | null {
|
|
return localStorage.getItem('jwt');
|
|
}
|
|
|
|
/**
|
|
* Save the JWT to localStorage
|
|
*/
|
|
private saveJwt(jwt: string): void {
|
|
localStorage.setItem('jwt', jwt);
|
|
|
|
const claims = this.extractJwtClaims(jwt);
|
|
console.log("User claims: ", claims);
|
|
this.userClaimsSubject.next(claims);
|
|
}
|
|
|
|
/**
|
|
* Extract claims from JWT
|
|
*/
|
|
private extractJwtClaims(jwt: string): JwtClaims {
|
|
return <JwtClaims>this.jwtHelper.decodeToken(jwt);
|
|
}
|
|
|
|
/**
|
|
* Get user authorizations from claims
|
|
*/
|
|
public getUserAuthorizations(): string[] {
|
|
const claims = this.userClaimsSubject.getValue();
|
|
return claims?.authorities || [];
|
|
}
|
|
|
|
public hasAccess(requiredAuthorizations: string[]): boolean {
|
|
const userAuthorizations = this.getUserAuthorizations();
|
|
return requiredAuthorizations.some(auth => userAuthorizations.includes(auth));
|
|
}
|
|
|
|
public getUuid(): string | null {
|
|
if (environment.defaultAuthStatus) {
|
|
return '55e46bc3-2a29-4c53-850f-dbd944dc5c5f';
|
|
}
|
|
const jwtClaims = this.userClaimsSubject.getValue();
|
|
if (jwtClaims === null) {
|
|
return null;
|
|
}
|
|
return jwtClaims.sub ?? null;
|
|
}
|
|
}
|