From 78399a6b1efd761cf39c0f9451be070210cec8f1 Mon Sep 17 00:00:00 2001 From: limcaaarl Date: Tue, 12 Nov 2024 23:14:07 +0800 Subject: [PATCH] Bug fix for #77 - Users will now be warned if their tokens are about to expire - Users will be logged out upon token expiration --- .../src/_services/authentication.service.ts | 35 +++++++++++++++++++ frontend/src/app/app.component.html | 1 + frontend/src/app/app.component.ts | 16 ++++++--- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/frontend/src/_services/authentication.service.ts b/frontend/src/_services/authentication.service.ts index 303303b39e..a3e4894f38 100644 --- a/frontend/src/_services/authentication.service.ts +++ b/frontend/src/_services/authentication.service.ts @@ -7,6 +7,7 @@ import { map, switchMap } from 'rxjs/operators'; import { UServRes } from '../_models/user.service.model'; import { User } from '../_models/user.model'; import { ApiService } from './api.service'; +import { ToastService } from './toast.service'; @Injectable({ providedIn: 'root' }) export class AuthenticationService extends ApiService { @@ -18,6 +19,7 @@ export class AuthenticationService extends ApiService { constructor( private router: Router, private http: HttpClient, + private toastService: ToastService, ) { super(); const userData = localStorage.getItem('user'); @@ -53,6 +55,8 @@ export class AuthenticationService extends ApiService { } localStorage.setItem('user', JSON.stringify(user)); this.userSubject.next(user); + this.startTokenExpiryCheck(); + return user; }), ); @@ -99,4 +103,35 @@ export class AuthenticationService extends ApiService { }), ); } + public startTokenExpiryCheck(): void { + const tokenExpirationTime = this.getTokenExpiration(); + + if (!tokenExpirationTime) { + this.logout(); + return; + } + + const oneMinute = 60 * 1000; + const checkInterval = oneMinute; + + setInterval(() => { + const now = Date.now(); + const timeLeft = tokenExpirationTime - now; + + if (timeLeft <= 0) { + this.toastService.showToast('Your session has expired. Please log in again.'); + this.logout(); + } else if (timeLeft < 5 * oneMinute) { + this.toastService.showToast('Your session will expire in less than 5 minutes. Please log in again'); + } + }, checkInterval); + } + + private getTokenExpiration() { + const user = this.userValue; + if (!user || !user.accessToken) return null; + + const tokenPayload = JSON.parse(atob(user.accessToken.split('.')[1])); + return tokenPayload.exp ? tokenPayload.exp * 1000 : null; + } } diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index a20a5cb8af..d702e4580e 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -1,4 +1,5 @@
+
diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index d0722c2b03..0e29dabf67 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -1,16 +1,24 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { ButtonModule } from 'primeng/button'; import { PasswordModule } from 'primeng/password'; +import { ToastModule } from 'primeng/toast'; import { NavigationBarComponent } from './navigation-bar/navigation-bar.component'; - +import { AuthenticationService } from '../_services/authentication.service'; +import { MessageService } from 'primeng/api'; @Component({ selector: 'app-root', standalone: true, - imports: [NavigationBarComponent, RouterOutlet, ButtonModule, PasswordModule], + imports: [NavigationBarComponent, RouterOutlet, ButtonModule, PasswordModule, ToastModule], + providers: [MessageService], templateUrl: './app.component.html', styleUrl: './app.component.css', }) -export class AppComponent { +export class AppComponent implements OnInit { title = 'frontend'; + + constructor(private authService: AuthenticationService) {} + ngOnInit() { + this.authService.startTokenExpiryCheck(); + } }