Skip to content

Commit 4b7efe0

Browse files
committed
front-end fix: should logout all tabs; should reload tabs on fresh login
1 parent c9dc9c8 commit 4b7efe0

File tree

7 files changed

+77
-46
lines changed

7 files changed

+77
-46
lines changed

angular/src/app/core/guards/auth.guard.ts

+13-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from '@angular/router';
99
import { Observable } from 'rxjs';
1010
import { AuthService } from '../services/auth.service';
11+
import { map } from 'rxjs/operators';
1112

1213
@Injectable({
1314
providedIn: 'root',
@@ -23,14 +24,17 @@ export class AuthGuard implements CanActivate {
2324
| Promise<boolean | UrlTree>
2425
| boolean
2526
| UrlTree {
26-
const user = this.authService.currentUser;
27-
if (user) {
28-
return true;
29-
} else {
30-
this.router.navigate(['login'], {
31-
queryParams: { returnUrl: state.url },
32-
});
33-
return false;
34-
}
27+
return this.authService.user$.pipe(
28+
map((user) => {
29+
if (user) {
30+
return true;
31+
} else {
32+
this.router.navigate(['login'], {
33+
queryParams: { returnUrl: state.url },
34+
});
35+
return false;
36+
}
37+
})
38+
);
3539
}
3640
}

angular/src/app/core/interceptors/unauthorized.interceptor.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,8 @@ export class UnauthorizedInterceptor implements HttpInterceptor {
2323
catchError((err) => {
2424
if (err.status === 401) {
2525
this.authService.clearLocalStorage();
26-
if (this.authService.currentUser) {
27-
this.authService.logout();
28-
} else {
29-
this.router.navigate(['']);
30-
}
26+
this.router.navigate(['login']);
27+
return;
3128
}
3229

3330
if (!environment.production) {
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
export interface ApplicationUser {
22
username: string;
33
role: string;
4-
accessToken: string;
5-
refreshToken: string;
64
}

angular/src/app/core/services/auth.service.ts

+43-21
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,56 @@
1-
import { Injectable } from '@angular/core';
1+
import { Injectable, OnDestroy } from '@angular/core';
22
import { Router } from '@angular/router';
33
import { HttpClient } from '@angular/common/http';
44
import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
55
import { map, tap, delay, finalize } from 'rxjs/operators';
66
import { ApplicationUser } from '../models/application-user';
77
import { environment } from 'src/environments/environment';
88

9+
interface LoginResult {
10+
username: string;
11+
role: string;
12+
accessToken: string;
13+
refreshToken: string;
14+
}
15+
916
@Injectable({
1017
providedIn: 'root',
1118
})
12-
export class AuthService {
19+
export class AuthService implements OnDestroy {
1320
private readonly apiUrl = `${environment.apiUrl}api/account`;
1421
private timer: Subscription;
1522
private _user = new BehaviorSubject<ApplicationUser>(null);
16-
public user$: Observable<ApplicationUser> = this._user.asObservable();
23+
user$: Observable<ApplicationUser> = this._user.asObservable();
24+
25+
private storageEventListener(event: StorageEvent) {
26+
if (event.storageArea === localStorage) {
27+
if (event.key === 'logout-event') {
28+
this._user.next(null);
29+
}
30+
if (event.key === 'login-event') {
31+
location.reload();
32+
}
33+
}
34+
}
1735

18-
constructor(private router: Router, private http: HttpClient) {}
36+
constructor(private router: Router, private http: HttpClient) {
37+
window.addEventListener('storage', this.storageEventListener.bind(this));
38+
}
1939

20-
public get currentUser(): ApplicationUser {
21-
return this._user.value;
40+
ngOnDestroy(): void {
41+
window.removeEventListener('storage', this.storageEventListener.bind(this));
2242
}
2343

2444
login(username: string, password: string) {
2545
return this.http
26-
.post<ApplicationUser>(`${this.apiUrl}/login`, { username, password })
46+
.post<LoginResult>(`${this.apiUrl}/login`, { username, password })
2747
.pipe(
28-
map((user) => {
29-
this._user.next(user);
30-
this.setLocalStorage(user);
48+
map((x) => {
49+
this._user.next({ username: x.username, role: x.role });
50+
this.setLocalStorage(x);
51+
localStorage.setItem('login-event', 'login' + Math.random());
3152
this.startTokenTimer();
32-
return user;
53+
return x;
3354
})
3455
);
3556
}
@@ -40,9 +61,10 @@ export class AuthService {
4061
.pipe(
4162
finalize(() => {
4263
this.clearLocalStorage();
43-
this.stopTokenTimer();
64+
localStorage.setItem('logout-event', 'logout' + Math.random());
4465
this._user.next(null);
45-
this.router.navigate(['']);
66+
this.stopTokenTimer();
67+
this.router.navigate(['login']);
4668
})
4769
)
4870
.subscribe();
@@ -56,20 +78,20 @@ export class AuthService {
5678
}
5779

5880
return this.http
59-
.post<ApplicationUser>(`${this.apiUrl}/refresh-token`, { refreshToken })
81+
.post<LoginResult>(`${this.apiUrl}/refresh-token`, { refreshToken })
6082
.pipe(
61-
map((user) => {
62-
this._user.next(user);
63-
this.setLocalStorage(user);
83+
map((x) => {
84+
this._user.next({ username: x.username, role: x.role });
85+
this.setLocalStorage(x);
6486
this.startTokenTimer();
65-
return user;
87+
return x;
6688
})
6789
);
6890
}
6991

70-
setLocalStorage(user: ApplicationUser) {
71-
localStorage.setItem('access_token', user.accessToken);
72-
localStorage.setItem('refresh_token', user.refreshToken);
92+
setLocalStorage(x: LoginResult) {
93+
localStorage.setItem('access_token', x.accessToken);
94+
localStorage.setItem('refresh_token', x.refreshToken);
7395
}
7496

7597
clearLocalStorage() {

angular/src/app/home/home.component.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ <h4 class="card-header">Hi {{ user.username }},</h4>
77
<div class="card-body">
88
<div class="m-2">
99
<h6>Your access token is</h6>
10-
{{ user.accessToken }}
10+
{{ accessToken }}
1111
</div>
1212
<div class="m-2">
1313
<h6>Your refresh token is</h6>
14-
{{ user.refreshToken }}
14+
{{ refreshToken }}
1515
</div>
1616
</div>
1717
</div>

angular/src/app/home/home.component.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ import { AuthService } from '../core';
77
styleUrls: ['./home.component.css'],
88
})
99
export class HomeComponent implements OnInit {
10+
accessToken = '';
11+
refreshToken = '';
12+
1013
constructor(public authService: AuthService) {}
1114

12-
ngOnInit(): void {}
15+
ngOnInit(): void {
16+
this.accessToken = localStorage.getItem('access_token');
17+
this.refreshToken = localStorage.getItem('refresh_token');
18+
}
1319
}

angular/src/app/login/login.component.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ export class LoginComponent implements OnInit {
1818
private route: ActivatedRoute,
1919
private router: Router,
2020
private authService: AuthService
21-
) {
22-
if (this.authService.currentUser) {
23-
this.router.navigate(['']);
24-
}
25-
}
21+
) {}
2622

27-
ngOnInit(): void {}
23+
ngOnInit(): void {
24+
this.authService.user$.subscribe((x) => {
25+
const accessToken = localStorage.getItem('access_token');
26+
const refreshToken = localStorage.getItem('refresh_token');
27+
if (x && accessToken && refreshToken) {
28+
this.router.navigate(['']);
29+
}
30+
});
31+
}
2832

2933
login() {
3034
if (!this.username || !this.password) {

0 commit comments

Comments
 (0)