@brggroup/share-lib 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/brggroup-share-lib.mjs +84 -17
- package/fesm2022/brggroup-share-lib.mjs.map +1 -1
- package/lib/auth/auth.interceptor.d.ts.map +1 -1
- package/lib/auth/auth.service.d.ts +1 -0
- package/lib/auth/auth.service.d.ts.map +1 -1
- package/lib/auth/token.storage.d.ts +4 -0
- package/lib/auth/token.storage.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
|
|
5
5
|
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
|
6
6
|
import * as i3 from '@ngx-translate/core';
|
|
7
7
|
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
|
8
|
-
import { firstValueFrom, BehaviorSubject, of, catchError,
|
|
8
|
+
import { firstValueFrom, BehaviorSubject, of, catchError, throwError, finalize, from, switchMap as switchMap$1, EMPTY, filter, take, fromEvent } from 'rxjs';
|
|
9
9
|
import { NzNotificationService } from 'ng-zorro-antd/notification';
|
|
10
10
|
import * as i1 from 'ng-zorro-antd/modal';
|
|
11
11
|
import { NzModalService } from 'ng-zorro-antd/modal';
|
|
@@ -409,6 +409,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
409
409
|
|
|
410
410
|
class TokenStorage {
|
|
411
411
|
static JWT_TOKEN = 'JWT_TOKEN';
|
|
412
|
+
static JWT_RFT_TOKEN = 'JWT_RFT_TOKEN';
|
|
412
413
|
static USER_NAME = 'username';
|
|
413
414
|
static FULL_NAME = 'fullname';
|
|
414
415
|
static USER_MENU = 'usermenu';
|
|
@@ -417,7 +418,15 @@ class TokenStorage {
|
|
|
417
418
|
static ORG_NAME = 'orgname';
|
|
418
419
|
static saveToken(tokenRes) {
|
|
419
420
|
AppStorage.tokenStorage.setItem(this.JWT_TOKEN, tokenRes.Data.Token);
|
|
420
|
-
|
|
421
|
+
AppStorage.tokenStorage.setItem(this.JWT_RFT_TOKEN, tokenRes.Data.RefreshToken);
|
|
422
|
+
TokenStorage.saveTokenInfo(tokenRes.Data.Token);
|
|
423
|
+
}
|
|
424
|
+
static saveTokenRft(token) {
|
|
425
|
+
AppStorage.tokenStorage.setItem(this.JWT_TOKEN, token);
|
|
426
|
+
TokenStorage.saveTokenInfo(token);
|
|
427
|
+
}
|
|
428
|
+
static saveTokenInfo(token) {
|
|
429
|
+
const userInfo = jwtDecode(token);
|
|
421
430
|
AppStorage.tokenStorage.setItem(this.USER_NAME, userInfo[this.USER_NAME]);
|
|
422
431
|
AppStorage.tokenStorage.setItem(this.FULL_NAME, userInfo[this.FULL_NAME]);
|
|
423
432
|
AppStorage.tokenStorage.setItem(this.ORG_ID, userInfo[this.ORG_ID]);
|
|
@@ -448,6 +457,9 @@ class TokenStorage {
|
|
|
448
457
|
static getToken() {
|
|
449
458
|
return AppStorage.tokenStorage.getItem(this.JWT_TOKEN);
|
|
450
459
|
}
|
|
460
|
+
static getRftToken() {
|
|
461
|
+
return AppStorage.tokenStorage.getItem(this.JWT_RFT_TOKEN);
|
|
462
|
+
}
|
|
451
463
|
static isLoggedIn() {
|
|
452
464
|
return AppStorage.tokenStorage.getItem(this.JWT_TOKEN) != null;
|
|
453
465
|
}
|
|
@@ -474,6 +486,21 @@ class AuthService extends HTTPService {
|
|
|
474
486
|
commonService = inject(CommonService);
|
|
475
487
|
router = inject(Router);
|
|
476
488
|
translate = inject(TranslateService);
|
|
489
|
+
async refreshToken() {
|
|
490
|
+
const refreshToken = TokenStorage.getRftToken();
|
|
491
|
+
if (!refreshToken)
|
|
492
|
+
return null;
|
|
493
|
+
const body = { rft: refreshToken };
|
|
494
|
+
try {
|
|
495
|
+
const result = (await firstValueFrom(this.httpClient.post(AppGlobals.apiEndpoint + '/api/Auth/RefreshToken', body)));
|
|
496
|
+
if (result?.IsSuccess) {
|
|
497
|
+
TokenStorage.saveTokenRft(result.Data);
|
|
498
|
+
return result;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch { }
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
477
504
|
async pingAuth() {
|
|
478
505
|
try {
|
|
479
506
|
const res = await this.post(AppGlobals.apiEndpoint + URLs.pingAuth);
|
|
@@ -616,23 +643,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
616
643
|
}] });
|
|
617
644
|
|
|
618
645
|
let initialReturnUrl = null;
|
|
646
|
+
let isRefreshing = false;
|
|
647
|
+
const refreshTokenSubject = new BehaviorSubject(null);
|
|
619
648
|
function authInterceptor(req, next) {
|
|
620
649
|
const router = inject(Router);
|
|
621
650
|
const loadingService = inject(LoadingService);
|
|
622
|
-
const
|
|
623
|
-
const notiService = inject(NotiService);
|
|
624
|
-
const translate = inject(TranslateService);
|
|
651
|
+
const authService = inject(AuthService);
|
|
625
652
|
const authToken = TokenStorage.getToken();
|
|
626
653
|
const noLoadingMark = req.headers.get('No-Loading-Mark');
|
|
627
|
-
if (noLoadingMark
|
|
654
|
+
if (noLoadingMark !== '1')
|
|
628
655
|
loadingService.loadingUp();
|
|
629
|
-
|
|
656
|
+
// Convert dates
|
|
630
657
|
if (!(req.body instanceof FormData)) {
|
|
631
658
|
const newBody = convertDatesInBody(req.body);
|
|
632
659
|
if (req.body !== newBody) {
|
|
633
660
|
req = req.clone({ body: newBody });
|
|
634
661
|
}
|
|
635
662
|
}
|
|
663
|
+
// Add token
|
|
636
664
|
if (authToken) {
|
|
637
665
|
req = req.clone({
|
|
638
666
|
setHeaders: { Authorization: `Bearer ${authToken}` },
|
|
@@ -640,8 +668,46 @@ function authInterceptor(req, next) {
|
|
|
640
668
|
}
|
|
641
669
|
return next(req).pipe(catchError((error) => {
|
|
642
670
|
if (error.status === 401) {
|
|
643
|
-
|
|
644
|
-
|
|
671
|
+
return handle401(req, next, router, authService);
|
|
672
|
+
}
|
|
673
|
+
return throwError(() => error);
|
|
674
|
+
}), finalize(() => {
|
|
675
|
+
if (noLoadingMark !== '1')
|
|
676
|
+
loadingService.loadingDown();
|
|
677
|
+
}));
|
|
678
|
+
}
|
|
679
|
+
//
|
|
680
|
+
// ⭐ REFRESH TOKEN HANDLER
|
|
681
|
+
//
|
|
682
|
+
function handle401(req, next, router, authService) {
|
|
683
|
+
if (!isRefreshing) {
|
|
684
|
+
isRefreshing = true;
|
|
685
|
+
refreshTokenSubject.next(null);
|
|
686
|
+
return from(authService.refreshToken()).pipe(switchMap$1((resAny) => {
|
|
687
|
+
const res = resAny;
|
|
688
|
+
isRefreshing = false;
|
|
689
|
+
if (!res?.IsSuccess) {
|
|
690
|
+
TokenStorage.clearToken();
|
|
691
|
+
const currentUrl = router.routerState.snapshot.url;
|
|
692
|
+
if (!initialReturnUrl && !currentUrl.startsWith('/login')) {
|
|
693
|
+
initialReturnUrl = currentUrl;
|
|
694
|
+
}
|
|
695
|
+
router.navigate(['/login'], {
|
|
696
|
+
queryParams: { returnUrl: initialReturnUrl || '/' },
|
|
697
|
+
});
|
|
698
|
+
return EMPTY;
|
|
699
|
+
}
|
|
700
|
+
// Lưu token mới
|
|
701
|
+
TokenStorage.saveToken(res);
|
|
702
|
+
// Phát token mới cho các request đang chờ
|
|
703
|
+
refreshTokenSubject.next(TokenStorage.getToken());
|
|
704
|
+
// Retry request
|
|
705
|
+
return next(req.clone({
|
|
706
|
+
setHeaders: { Authorization: `Bearer ${TokenStorage.getToken()}` },
|
|
707
|
+
}));
|
|
708
|
+
}), catchError((err) => {
|
|
709
|
+
isRefreshing = false;
|
|
710
|
+
TokenStorage.clearToken();
|
|
645
711
|
const currentUrl = router.routerState.snapshot.url;
|
|
646
712
|
if (!initialReturnUrl && !currentUrl.startsWith('/login')) {
|
|
647
713
|
initialReturnUrl = currentUrl;
|
|
@@ -649,14 +715,15 @@ function authInterceptor(req, next) {
|
|
|
649
715
|
router.navigate(['/login'], {
|
|
650
716
|
queryParams: { returnUrl: initialReturnUrl || '/' },
|
|
651
717
|
});
|
|
652
|
-
return
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
718
|
+
return throwError(() => err);
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
// Nếu đang refresh → chờ token mới rồi retry
|
|
723
|
+
return refreshTokenSubject.pipe(filter((token) => token != null), take(1), switchMap$1((token) => next(req.clone({
|
|
724
|
+
setHeaders: { Authorization: `Bearer ${token}` },
|
|
725
|
+
}))));
|
|
726
|
+
}
|
|
660
727
|
}
|
|
661
728
|
function convertDatesInBody(obj) {
|
|
662
729
|
if (obj instanceof Date) {
|