Add JWT support for authentication handling
Integrate `@auth0/angular-jwt` for Token management. Update `app.config.ts` with `JwtModule` setup and token getter from cookies. Enhance `AuthService` to include token handling, fake login, and JWT validation using `JwtHelperService`. Introduce `JwtClaims` interface for structured token claims.
This commit is contained in:
parent
dfea91d8ca
commit
f0faa63ca7
|
|
@ -22,6 +22,7 @@
|
|||
"@angular/platform-browser": "^19.2.0",
|
||||
"@angular/platform-browser-dynamic": "^19.2.0",
|
||||
"@angular/router": "^19.2.0",
|
||||
"@auth0/angular-jwt": "^5.2.0",
|
||||
"@types/three": "^0.177.0",
|
||||
"ngx-cookie-service": "^19.1.2",
|
||||
"rxjs": "~7.8.0",
|
||||
|
|
|
|||
|
|
@ -1,8 +1,26 @@
|
|||
import {ApplicationConfig, provideZoneChangeDetection} from '@angular/core';
|
||||
import {provideRouter} from '@angular/router';
|
||||
import {JwtHelperService, JwtModule} from '@auth0/angular-jwt';
|
||||
import {CookieService} from 'ngx-cookie-service';
|
||||
|
||||
import {routes} from './app.routes';
|
||||
|
||||
// Function to get the JWT token from cookies
|
||||
export function jwtTokenGetter() {
|
||||
const cookieService = new CookieService(document, null);
|
||||
return cookieService.check('jwt') ? cookieService.get('jwt') : null;
|
||||
}
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [provideZoneChangeDetection({eventCoalescing: true}), provideRouter(routes)]
|
||||
providers: [
|
||||
provideZoneChangeDetection({eventCoalescing: true}),
|
||||
provideRouter(routes),
|
||||
{ provide: CookieService, useClass: CookieService },
|
||||
{ provide: JwtHelperService, useClass: JwtHelperService },
|
||||
{ provide: JwtModule, useValue: JwtModule.forRoot({
|
||||
config: {
|
||||
tokenGetter: jwtTokenGetter
|
||||
}
|
||||
})}
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {CookieService} from 'ngx-cookie-service';
|
|||
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';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
|
@ -12,13 +13,14 @@ export class AuthService {
|
|||
private isAuthenticatedSubject = new BehaviorSubject<boolean>(false);
|
||||
public isAuthenticated$ = this.isAuthenticatedSubject.asObservable();
|
||||
|
||||
private userClaimsSubject = new BehaviorSubject<any>(null);
|
||||
private userClaimsSubject = new BehaviorSubject<JwtClaims | null>(null);
|
||||
public userClaims$ = this.userClaimsSubject.asObservable();
|
||||
|
||||
constructor(
|
||||
private loginService: LoginService,
|
||||
private cookieService: CookieService,
|
||||
private snackBar: MatSnackBar
|
||||
private snackBar: MatSnackBar,
|
||||
private jwtHelper: JwtHelperService
|
||||
) {
|
||||
// Check if user is already logged in on service initialization
|
||||
this.checkAuthStatus();
|
||||
|
|
@ -30,7 +32,7 @@ export class AuthService {
|
|||
public login(code: string): Observable<any> {
|
||||
return this.loginService.login(code).pipe(
|
||||
tap(jwt => {
|
||||
this.saveJwt(jwt as JsonWebKey);
|
||||
this.saveJwt(jwt);
|
||||
this.isAuthenticatedSubject.next(true);
|
||||
}),
|
||||
catchError(error => {
|
||||
|
|
@ -40,6 +42,13 @@ export class AuthService {
|
|||
);
|
||||
}
|
||||
|
||||
public fakeLogin(): Observable<any> {
|
||||
const jwt = 'ZXlKaGJHY2lPaUpTVXpJMU5pSjkuZXlKcGMzTWlPaUpoYkhScGRIVmtaWGRsWWlJc0luTjFZaUk2SWpVMVpUUTJZbU16TFRKaE1qa3ROR00xTXkwNE5UQm1MV1JpWkRrME5HUmpOV00xWmlJc0ltVjRjQ0k2TVRjMU5ESTFNREUyTkN3aWFXRjBJam94TnpVeE5qVTRNVFkwTENKaGRYUm9iM0pwZEdsbGN5STZXeUpUUTA5UVJWOTFjMlZ5SWwxOS5iWU5Ba0hjUEp5ektReTl0cjN2RFB2VUNyX0FtQTNNVEtrZmlLV0dzV2M1QTdjR3ZKay1UYmQzdEJzYU1LZjI0ZUotZmtudjEyWFBGaXRXSmdRRVdNYTJvc19EYWkwZm1kT1J3MUlRb2d5bndOamtnWjBnMUJfU1lCMVRpZV9YQXpJTkNJSkNXMHB4YTB5U0dQUWxPaTJjVE1uWjdlRDlHMkI5NW0tcklMNG9NVDJMa3NwSjR2NXNCSlVrclNEaEl2dkQxOUhvWlFNV0VpU3BUbkQxVVhCSC1NVFVBMWhSSUFaZEd1cTVfWmpsQWNpMlpya195c0ZreGZBYVZHRW4zQXlpMFNmMjZhbEFlSGVxaW90M1lvWDR5djYyd0treThaODdkZVdMcWxvUHBzdi1INXNVX1E3dzhMano4cS1Ecl9hMHVRMlF2bDc4Y1RDV1JtTm04dlE=';
|
||||
this.saveJwt(jwt);
|
||||
this.isAuthenticatedSubject.next(true);
|
||||
return undefined as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the user out by removing the JWT
|
||||
*/
|
||||
|
|
@ -56,14 +65,13 @@ export class AuthService {
|
|||
const jwt = this.getJwt();
|
||||
if (jwt) {
|
||||
try {
|
||||
const claims = this.extractJwtClaims(jwt as JsonWebKey);
|
||||
// Check if token is expired
|
||||
const currentTime = Math.floor(Date.now() / 1000);
|
||||
if (claims.exp && claims.exp < currentTime) {
|
||||
if (this.jwtHelper.isTokenExpired(jwt)) {
|
||||
this.logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
const claims = this.extractJwtClaims(jwt);
|
||||
this.userClaimsSubject.next(claims);
|
||||
this.isAuthenticatedSubject.next(true);
|
||||
return true;
|
||||
|
|
@ -84,8 +92,8 @@ export class AuthService {
|
|||
/**
|
||||
* Save the JWT to cookies
|
||||
*/
|
||||
private saveJwt(jwt: JsonWebKey): void {
|
||||
this.cookieService.set('jwt', jwt.toString(), {
|
||||
private saveJwt(jwt: string): void {
|
||||
this.cookieService.set('jwt', jwt, {
|
||||
path: '/',
|
||||
secure: true,
|
||||
sameSite: 'Strict'
|
||||
|
|
@ -93,16 +101,14 @@ export class AuthService {
|
|||
|
||||
const claims = this.extractJwtClaims(jwt);
|
||||
this.userClaimsSubject.next(claims);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract claims from JWT
|
||||
*/
|
||||
private extractJwtClaims(jwt: JsonWebKey): any {
|
||||
const token = jwt.toString();
|
||||
const base64Url = token.split('.')[1];
|
||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
||||
return JSON.parse(window.atob(base64));
|
||||
private extractJwtClaims(jwt: string): JwtClaims {
|
||||
return <JwtClaims>this.jwtHelper.decodeToken(jwt);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ export class LoginDialogComponent {
|
|||
return;
|
||||
}
|
||||
this.snackBar.open('Logging in...', '', {duration: 2000});
|
||||
this.authService.login(this.loginForm.value.code).subscribe({
|
||||
// this.authService.login(this.loginForm.value.code).subscribe({
|
||||
this.authService.fakeLogin().subscribe({
|
||||
next: (jwt) => {
|
||||
this.dialogRef.close(jwt);
|
||||
},
|
||||
|
|
|
|||
7
frontend/src/app/types/jwt_interface.ts
Normal file
7
frontend/src/app/types/jwt_interface.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
interface JwtClaims {
|
||||
iss?: string;
|
||||
sub?: string;
|
||||
iat?: number;
|
||||
exp?: number;
|
||||
authorizations?: string[];
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user