source: Farmatiko/ClientApp/src/app/shared/services/auth.service.ts@ 1f4846d

Last change on this file since 1f4846d was 1f4846d, checked in by Mile Jankuloski <mile.jankuloski@…>, 2 years ago

Jwt token auth interceptors, services and guards

  • Property mode set to 100644
File size: 4.0 KB
RevLine 
[1f4846d]1import { Injectable, OnDestroy } from '@angular/core';
2import { Router } from '@angular/router';
3import { HttpClient } from '@angular/common/http';
4import { BehaviorSubject, Observable, of, Subscription } from 'rxjs';
5import { map, tap, delay, finalize } from 'rxjs/operators';
6import { IPharmacyHead } from '../interfaces';
7import { environment } from '../../../environments/environment';
8
9
10interface LoginResult {
11 username: string;
12 role: string;
13 accessToken: string;
14 refreshToken: string;
15 head: IPharmacyHead;
16}
17
18@Injectable({
19 providedIn: 'root',
20})
21export class AuthService implements OnDestroy {
22 private readonly apiUrl = `${environment.baseApiUrl}api/pharmacyhead`;
23 private timer: Subscription;
24 private _user = new BehaviorSubject<IPharmacyHead>(null);
25 user$: Observable<IPharmacyHead> = this._user.asObservable();
26
27 private storageEventListener(event: StorageEvent) {
28 if (event.storageArea === localStorage) {
29 if (event.key === 'logout-event') {
30 this.stopTokenTimer();
31 this._user.next(null);
32 }
33 if (event.key === 'login-event') {
34 this.stopTokenTimer();
35 this.http.get<LoginResult>(`${this.apiUrl}/user`).subscribe((x) => {
36 this._user.next({
37 Email: x.username,
38 Role: x.role,
39 Passwd: x.head.Passwd,
40 Name: x.head.Name
41 });
42 });
43 }
44 }
45 }
46
47 constructor(private router: Router, private http: HttpClient) {
48 window.addEventListener('storage', this.storageEventListener.bind(this));
49 console.log(this.apiUrl);
50 }
51
52 ngOnDestroy(): void {
53 window.removeEventListener('storage', this.storageEventListener.bind(this));
54 }
55
56 login(username: string, password: string) {
57 return this.http
58 .post<LoginResult>(`${this.apiUrl}/login`, { username, password })
59 .pipe(
60 map((x) => {
61 this._user.next({
62 Email: x.username,
63 Role: x.role,
64 Passwd: x.head.Passwd,
65 Name: x.head.Name
66 });
67 this.setLocalStorage(x);
68 this.startTokenTimer();
69 return x;
70 })
71 );
72 }
73
74 logout() {
75 this.http
76 .post<unknown>(`${this.apiUrl}/logout`, {})
77 .pipe(
78 finalize(() => {
79 this.clearLocalStorage();
80 this._user.next(null);
81 this.stopTokenTimer();
82 this.router.navigate(['login']);
83 })
84 )
85 .subscribe();
86 }
87
88 refreshToken() {
89 const refreshToken = localStorage.getItem('refresh_token');
90 if (!refreshToken) {
91 this.clearLocalStorage();
92 return of(null);
93 }
94
95 return this.http
96 .post<LoginResult>(`${this.apiUrl}/refresh-token`, { refreshToken })
97 .pipe(
98 map((x) => {
99 this._user.next({
100 Email: x.username,
101 Role: x.role,
102 Passwd: x.head.Passwd,
103 Name: x.head.Name
104 });
105 this.setLocalStorage(x);
106 this.startTokenTimer();
107 return x;
108 })
109 );
110 }
111
112 setLocalStorage(x: LoginResult) {
113 localStorage.setItem('access_token', x.accessToken);
114 localStorage.setItem('refresh_token', x.refreshToken);
115 localStorage.setItem('login-event', 'login' + Math.random());
116 }
117
118 clearLocalStorage() {
119 localStorage.removeItem('access_token');
120 localStorage.removeItem('refresh_token');
121 localStorage.setItem('logout-event', 'logout' + Math.random());
122 }
123
124 getUser() {
125 return this.user$;
126 }
127
128 private getTokenRemainingTime() {
129 const accessToken = localStorage.getItem('access_token');
130 if (!accessToken) {
131 return 0;
132 }
133 const jwtToken = JSON.parse(atob(accessToken.split('.')[1]));
134 const expires = new Date(jwtToken.exp * 1000);
135 return expires.getTime() - Date.now();
136 }
137
138 private startTokenTimer() {
139 const timeout = this.getTokenRemainingTime();
140 this.timer = of(true)
141 .pipe(
142 delay(timeout),
143 tap(() => this.refreshToken().subscribe())
144 )
145 .subscribe();
146 }
147
148 private stopTokenTimer() {
149 this.timer?.unsubscribe();
150 }
151}
Note: See TracBrowser for help on using the repository browser.