@brggroup/share-lib 0.0.30 → 0.0.32
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 +142 -20
- 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 +13 -0
- package/lib/auth/auth.service.d.ts.map +1 -1
- package/lib/auth/token.storage.d.ts +2 -0
- package/lib/auth/token.storage.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, Injectable, Component, HostListener, ViewContainerRef, Input, ViewChild, EventEmitter, Output, Directive, Optional, Self, HostBinding, forwardRef, Pipe } from '@angular/core';
|
|
2
|
+
import { inject, Injectable, NgZone, Component, HostListener, ViewContainerRef, Input, ViewChild, EventEmitter, Output, Directive, Optional, Self, HostBinding, forwardRef, Pipe } from '@angular/core';
|
|
3
3
|
import * as i1$3 from '@angular/router';
|
|
4
4
|
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';
|
|
@@ -419,7 +419,14 @@ class TokenStorage {
|
|
|
419
419
|
static saveToken(tokenRes) {
|
|
420
420
|
AppStorage.tokenStorage.setItem(this.JWT_TOKEN, tokenRes.Data.Token);
|
|
421
421
|
AppStorage.tokenStorage.setItem(this.JWT_RFT_TOKEN, tokenRes.Data.RefreshToken);
|
|
422
|
-
|
|
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);
|
|
423
430
|
AppStorage.tokenStorage.setItem(this.USER_NAME, userInfo[this.USER_NAME]);
|
|
424
431
|
AppStorage.tokenStorage.setItem(this.FULL_NAME, userInfo[this.FULL_NAME]);
|
|
425
432
|
AppStorage.tokenStorage.setItem(this.ORG_ID, userInfo[this.ORG_ID]);
|
|
@@ -470,6 +477,7 @@ class TokenStorage {
|
|
|
470
477
|
|
|
471
478
|
const URLs = {
|
|
472
479
|
login: '/api/Auth/Login',
|
|
480
|
+
register: '/api/Auth/Register',
|
|
473
481
|
pingAuth: '/api/Auth/PingAuth',
|
|
474
482
|
changePassword: '/api/Auth/ChangePassword',
|
|
475
483
|
setPass: '/api/Auth/SetPass',
|
|
@@ -477,11 +485,32 @@ const URLs = {
|
|
|
477
485
|
class AuthService extends HTTPService {
|
|
478
486
|
notiService = inject(NotiService);
|
|
479
487
|
commonService = inject(CommonService);
|
|
488
|
+
ngZone = inject(NgZone);
|
|
480
489
|
router = inject(Router);
|
|
481
490
|
translate = inject(TranslateService);
|
|
491
|
+
async refreshToken() {
|
|
492
|
+
const refreshToken = TokenStorage.getRftToken();
|
|
493
|
+
if (!refreshToken)
|
|
494
|
+
return null;
|
|
495
|
+
const body = { rft: refreshToken };
|
|
496
|
+
try {
|
|
497
|
+
const res = await this.sendRftToken(body);
|
|
498
|
+
if (res?.IsSuccess) {
|
|
499
|
+
TokenStorage.saveTokenRft(res.Data);
|
|
500
|
+
return res;
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
catch (err) {
|
|
507
|
+
console.log(err);
|
|
508
|
+
}
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
482
511
|
async pingAuth() {
|
|
483
512
|
try {
|
|
484
|
-
const res = await this.
|
|
513
|
+
const res = await this.get(AppGlobals.apiEndpoint + URLs.pingAuth, true);
|
|
485
514
|
return res?.IsSuccess;
|
|
486
515
|
}
|
|
487
516
|
catch {
|
|
@@ -502,6 +531,7 @@ class AuthService extends HTTPService {
|
|
|
502
531
|
}
|
|
503
532
|
this.notiService.success('Đăng nhập thành công');
|
|
504
533
|
TokenStorage.saveToken(res);
|
|
534
|
+
this.startWatching();
|
|
505
535
|
if (returnUrl) {
|
|
506
536
|
this.router.navigateByUrl(returnUrl);
|
|
507
537
|
}
|
|
@@ -517,9 +547,18 @@ class AuthService extends HTTPService {
|
|
|
517
547
|
headers: new HttpHeaders().set('Content-Type', 'application/json'),
|
|
518
548
|
}));
|
|
519
549
|
}
|
|
550
|
+
async sendRftToken(body) {
|
|
551
|
+
return firstValueFrom(this.httpClient.post(AppGlobals.apiEndpoint + '/api/Auth/RefreshToken', body, {
|
|
552
|
+
headers: new HttpHeaders().set('Content-Type', 'application/json'),
|
|
553
|
+
}));
|
|
554
|
+
}
|
|
520
555
|
signOut() {
|
|
521
556
|
TokenStorage.clearToken();
|
|
522
|
-
this.
|
|
557
|
+
this.stopWatching();
|
|
558
|
+
const currentUrl = this.router.routerState.snapshot.url;
|
|
559
|
+
this.router.navigate(['/login'], {
|
|
560
|
+
queryParams: { returnUrl: currentUrl || '/' },
|
|
561
|
+
});
|
|
523
562
|
}
|
|
524
563
|
getUserMenu() {
|
|
525
564
|
let data = {
|
|
@@ -546,6 +585,51 @@ class AuthService extends HTTPService {
|
|
|
546
585
|
setPass(data) {
|
|
547
586
|
return this.postData(AppGlobals.apiEndpoint + URLs.setPass, data);
|
|
548
587
|
}
|
|
588
|
+
async signUp(d) {
|
|
589
|
+
try {
|
|
590
|
+
const res = await this.sendSignUp(d);
|
|
591
|
+
if (!res.IsSuccess) {
|
|
592
|
+
this.notiService.error(res.ErrorMessage);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
this.notiService.success('Đăng ký thành công');
|
|
596
|
+
this.router.navigateByUrl('/login');
|
|
597
|
+
}
|
|
598
|
+
catch (err) {
|
|
599
|
+
console.log(err);
|
|
600
|
+
this.notiService.handleError(err);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async sendSignUp(d) {
|
|
604
|
+
return this.postData(AppGlobals.apiEndpoint + URLs.register, d);
|
|
605
|
+
}
|
|
606
|
+
idleTimer;
|
|
607
|
+
idleTimeInMinutes = 15; // phút
|
|
608
|
+
idleTime = this.idleTimeInMinutes * 60 * 1000;
|
|
609
|
+
startWatching() {
|
|
610
|
+
console.log(`-- start watching idle (${this.idleTimeInMinutes} ${this.idleTimeInMinutes == 1 ? 'min' : 'mins'}) --`);
|
|
611
|
+
this.resetTimer();
|
|
612
|
+
window.addEventListener('mousemove', () => this.resetTimer());
|
|
613
|
+
window.addEventListener('keydown', () => this.resetTimer());
|
|
614
|
+
window.addEventListener('click', () => this.resetTimer());
|
|
615
|
+
}
|
|
616
|
+
resetTimer() {
|
|
617
|
+
if (this.idleTimer) {
|
|
618
|
+
clearTimeout(this.idleTimer);
|
|
619
|
+
}
|
|
620
|
+
this.ngZone.runOutsideAngular(() => {
|
|
621
|
+
this.idleTimer = setTimeout(() => {
|
|
622
|
+
this.ngZone.run(() => {
|
|
623
|
+
console.log('-- idle logout --');
|
|
624
|
+
this.signOut(); // auto logout
|
|
625
|
+
});
|
|
626
|
+
}, this.idleTime);
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
stopWatching() {
|
|
630
|
+
console.log('-- stop watching idle --');
|
|
631
|
+
clearTimeout(this.idleTimer);
|
|
632
|
+
}
|
|
549
633
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthService, deps: null, target: i0.ɵɵFactoryTarget.Injectable });
|
|
550
634
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.7", ngImport: i0, type: AuthService, providedIn: 'root' });
|
|
551
635
|
}
|
|
@@ -621,23 +705,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.7", ngImpor
|
|
|
621
705
|
}] });
|
|
622
706
|
|
|
623
707
|
let initialReturnUrl = null;
|
|
708
|
+
let isRefreshing = false;
|
|
709
|
+
const refreshTokenSubject = new BehaviorSubject(null);
|
|
624
710
|
function authInterceptor(req, next) {
|
|
625
711
|
const router = inject(Router);
|
|
626
712
|
const loadingService = inject(LoadingService);
|
|
627
|
-
const
|
|
628
|
-
const notiService = inject(NotiService);
|
|
629
|
-
const translate = inject(TranslateService);
|
|
713
|
+
const authService = inject(AuthService);
|
|
630
714
|
const authToken = TokenStorage.getToken();
|
|
631
715
|
const noLoadingMark = req.headers.get('No-Loading-Mark');
|
|
632
|
-
if (noLoadingMark
|
|
716
|
+
if (noLoadingMark !== '1')
|
|
633
717
|
loadingService.loadingUp();
|
|
634
|
-
|
|
718
|
+
// Convert dates
|
|
635
719
|
if (!(req.body instanceof FormData)) {
|
|
636
720
|
const newBody = convertDatesInBody(req.body);
|
|
637
721
|
if (req.body !== newBody) {
|
|
638
722
|
req = req.clone({ body: newBody });
|
|
639
723
|
}
|
|
640
724
|
}
|
|
725
|
+
// Add token
|
|
641
726
|
if (authToken) {
|
|
642
727
|
req = req.clone({
|
|
643
728
|
setHeaders: { Authorization: `Bearer ${authToken}` },
|
|
@@ -645,8 +730,44 @@ function authInterceptor(req, next) {
|
|
|
645
730
|
}
|
|
646
731
|
return next(req).pipe(catchError((error) => {
|
|
647
732
|
if (error.status === 401) {
|
|
648
|
-
|
|
649
|
-
|
|
733
|
+
return handle401(req, next, router, authService);
|
|
734
|
+
}
|
|
735
|
+
return throwError(() => error);
|
|
736
|
+
}), finalize(() => {
|
|
737
|
+
if (noLoadingMark !== '1')
|
|
738
|
+
loadingService.loadingDown();
|
|
739
|
+
}));
|
|
740
|
+
}
|
|
741
|
+
//
|
|
742
|
+
// ⭐ REFRESH TOKEN HANDLER
|
|
743
|
+
//
|
|
744
|
+
function handle401(req, next, router, authService) {
|
|
745
|
+
if (!isRefreshing) {
|
|
746
|
+
isRefreshing = true;
|
|
747
|
+
refreshTokenSubject.next(null);
|
|
748
|
+
return from(authService.refreshToken()).pipe(switchMap$1((resAny) => {
|
|
749
|
+
const res = resAny;
|
|
750
|
+
isRefreshing = false;
|
|
751
|
+
if (!res?.IsSuccess) {
|
|
752
|
+
const currentUrl = router.routerState.snapshot.url;
|
|
753
|
+
if (!initialReturnUrl && !currentUrl.startsWith('/login')) {
|
|
754
|
+
initialReturnUrl = currentUrl;
|
|
755
|
+
}
|
|
756
|
+
router.navigate(['/login'], {
|
|
757
|
+
queryParams: { returnUrl: initialReturnUrl || '/' },
|
|
758
|
+
});
|
|
759
|
+
refreshTokenSubject.next(null);
|
|
760
|
+
return EMPTY;
|
|
761
|
+
}
|
|
762
|
+
// Phát token mới cho các request đang chờ
|
|
763
|
+
refreshTokenSubject.next(TokenStorage.getToken());
|
|
764
|
+
// Retry request
|
|
765
|
+
return next(req.clone({
|
|
766
|
+
setHeaders: { Authorization: `Bearer ${TokenStorage.getToken()}` },
|
|
767
|
+
}));
|
|
768
|
+
}), catchError((err) => {
|
|
769
|
+
isRefreshing = false;
|
|
770
|
+
TokenStorage.clearToken();
|
|
650
771
|
const currentUrl = router.routerState.snapshot.url;
|
|
651
772
|
if (!initialReturnUrl && !currentUrl.startsWith('/login')) {
|
|
652
773
|
initialReturnUrl = currentUrl;
|
|
@@ -654,14 +775,15 @@ function authInterceptor(req, next) {
|
|
|
654
775
|
router.navigate(['/login'], {
|
|
655
776
|
queryParams: { returnUrl: initialReturnUrl || '/' },
|
|
656
777
|
});
|
|
657
|
-
return
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
778
|
+
return throwError(() => err);
|
|
779
|
+
}));
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
// Nếu đang refresh → chờ token mới rồi retry
|
|
783
|
+
return refreshTokenSubject.pipe(filter((token) => token != null), take(1), switchMap$1((token) => next(req.clone({
|
|
784
|
+
setHeaders: { Authorization: `Bearer ${token}` },
|
|
785
|
+
}))));
|
|
786
|
+
}
|
|
665
787
|
}
|
|
666
788
|
function convertDatesInBody(obj) {
|
|
667
789
|
if (obj instanceof Date) {
|