-เพิ่ม pkg jose ไว้ encrypt secret key
All checks were successful
Build Docker Image / Build Docker Image (push) Successful in 6m5s
All checks were successful
Build Docker Image / Build Docker Image (push) Successful in 6m5s
-jwt services/jwt.service.ts -เพิ่ม เวลา expire jwt token
This commit is contained in:
96
ng-ttc-frontend/src/app/services/jwt.service.ts
Normal file
96
ng-ttc-frontend/src/app/services/jwt.service.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { environment } from '../../environments/environment';
|
||||
import * as jose from 'jose';
|
||||
import { BehaviorSubject, Observable, timer, Subscription } from 'rxjs';
|
||||
import { map, takeWhile, finalize } from 'rxjs/operators';
|
||||
import { Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class JwtService {
|
||||
private secret = new TextEncoder().encode(environment.jwt_secret);
|
||||
private countdownSub = new BehaviorSubject<string | null>(null);
|
||||
public countdown$: Observable<string | null> = this.countdownSub.asObservable();
|
||||
private timerSubscription: Subscription | null = null;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private toastr: ToastrService
|
||||
) {
|
||||
this.startTokenCountdown();
|
||||
}
|
||||
|
||||
async decodeToken(token: string): Promise<any> {
|
||||
try {
|
||||
const { payload } = await jose.jwtVerify(token, this.secret);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
// console.error('Invalid token:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private startTokenCountdown(): void {
|
||||
if (this.timerSubscription) {
|
||||
this.timerSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
const token = localStorage.getItem('access_token');
|
||||
if (!token) {
|
||||
this.countdownSub.next(null);
|
||||
return;
|
||||
}
|
||||
|
||||
this.decodeToken(token).then(payload => {
|
||||
if (payload && payload.exp) {
|
||||
const expirationTime = payload.exp * 1000;
|
||||
this.timerSubscription = timer(0, 1000).pipe(
|
||||
map(() => {
|
||||
const now = new Date().getTime();
|
||||
const distance = expirationTime - now;
|
||||
|
||||
if (distance < 0) {
|
||||
this.logout();
|
||||
return 'Expired';
|
||||
}
|
||||
|
||||
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
|
||||
const seconds = Math.floor((distance % (1000 * 60)) / 1000);
|
||||
|
||||
return `${this.pad(hours)}:${this.pad(minutes)}:${this.pad(seconds)}`;
|
||||
}),
|
||||
takeWhile(val => val !== 'Expired', true),
|
||||
finalize(() => {
|
||||
if (this.countdownSub.value !== 'Expired') {
|
||||
this.logout();
|
||||
}
|
||||
this.countdownSub.next('Expired');
|
||||
})
|
||||
).subscribe(val => this.countdownSub.next(val));
|
||||
} else {
|
||||
this.countdownSub.next(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private pad(num: number): string {
|
||||
return num < 10 ? '0' + num : num.toString();
|
||||
}
|
||||
|
||||
public logout(): void {
|
||||
localStorage.removeItem('access_token');
|
||||
this.countdownSub.next(null);
|
||||
if (this.timerSubscription) {
|
||||
this.timerSubscription.unsubscribe();
|
||||
}
|
||||
// this.toastr.info('Your session has expired. Please log in again.', 'Session Expired');
|
||||
this.router.navigate(['/login']); // Assuming '/login' is your login route
|
||||
}
|
||||
|
||||
public restartCountdown(): void {
|
||||
this.startTokenCountdown();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user