|
|
import { Injectable } from '@angular/core'; |
|
|
import { BehaviorSubject } from 'rxjs'; |
|
|
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'; |
|
|
import { Observable } from 'rxjs/internal/Observable'; |
|
|
import { tap } from 'rxjs/operators'; |
|
|
import { catchError } from 'rxjs/operators'; |
|
|
import { throwError } from 'rxjs'; |
|
|
@Injectable({ |
|
|
providedIn: 'root' |
|
|
}) |
|
|
export class AuthenticationService { |
|
|
private apiUrl = 'http://127.0.0.1:5000'; |
|
|
private loggedInSubject = new BehaviorSubject<boolean>(this.isLoggedIn()); |
|
|
|
|
|
constructor(private http: HttpClient) { |
|
|
|
|
|
setInterval(() => this.checkAndRefreshToken(), 30 * 1000); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
login(username: string, password: string): Observable<any> { |
|
|
const loginData = { username, password }; |
|
|
return this.http.post(`${this.apiUrl}/login`, loginData).pipe( |
|
|
tap((response: any) => { |
|
|
|
|
|
|
|
|
localStorage.setItem('access_token', response.access_token); |
|
|
localStorage.setItem('refresh_token', response.refresh_token); |
|
|
|
|
|
|
|
|
|
|
|
const accessTokenExpiry = Date.now() + 2 * 60 * 1000; |
|
|
localStorage.setItem('access_token_expiry', accessTokenExpiry.toString()); |
|
|
|
|
|
|
|
|
const refreshTokenExpiry = Date.now() + 10 * 60 * 1000; |
|
|
localStorage.setItem('refresh_token_expiry', refreshTokenExpiry.toString()); |
|
|
|
|
|
this.loggedInSubject.next(true); |
|
|
|
|
|
}), |
|
|
catchError(error => { |
|
|
|
|
|
if (error.status === 401 && error.error.message === 'Token has expired') { |
|
|
|
|
|
} |
|
|
return throwError(error); |
|
|
}) |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logout(): Observable<any> { |
|
|
const token = this.getToken(); |
|
|
console.log('π Token at logout start:', token); |
|
|
|
|
|
this.removeToken(); |
|
|
this.loggedInSubject.next(false); |
|
|
|
|
|
if (!token) { |
|
|
console.warn('β οΈ No token found. Emitting success anyway.'); |
|
|
return new Observable(observer => { |
|
|
observer.next(true); |
|
|
observer.complete(); |
|
|
}); |
|
|
} |
|
|
|
|
|
const headers = new HttpHeaders().set('Authorization', `Bearer ${token}`); |
|
|
console.log('π€ Sending logout request with headers:', headers); |
|
|
|
|
|
return this.http.post(`${this.apiUrl}/logout`, {}, { headers }).pipe( |
|
|
tap(() => { |
|
|
console.log('β
Logout API request completed'); |
|
|
}), |
|
|
catchError((error) => { |
|
|
console.error('β Logout error in service:', error); |
|
|
return new Observable(observer => { |
|
|
observer.next(true); |
|
|
observer.complete(); |
|
|
}); |
|
|
}) |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getToken(): string | null { |
|
|
return localStorage.getItem('access_token'); |
|
|
} |
|
|
|
|
|
|
|
|
storeToken(token: string): void { |
|
|
localStorage.setItem('access_token', token); |
|
|
console.log('Token stored:', token); |
|
|
this.loggedInSubject.next(true); |
|
|
} |
|
|
|
|
|
removeToken(): void { |
|
|
localStorage.removeItem('access_token'); |
|
|
localStorage.removeItem('refresh_token'); |
|
|
localStorage.removeItem('access_token_expiry'); |
|
|
this.loggedInSubject.next(false); |
|
|
} |
|
|
|
|
|
|
|
|
isLoggedIn(): boolean { |
|
|
return !!this.getToken(); |
|
|
} |
|
|
|
|
|
get isLoggedIn$(): Observable<boolean> { |
|
|
return this.loggedInSubject.asObservable(); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
checkAndRefreshToken() { |
|
|
const accessTokenExpiry = localStorage.getItem('access_token_expiry'); |
|
|
if (accessTokenExpiry && Date.now() >= (+accessTokenExpiry - 5000)) { |
|
|
|
|
|
this.refreshAccessToken(); |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
refreshAccessToken() { |
|
|
const refreshToken = localStorage.getItem('refresh_token'); |
|
|
|
|
|
if (refreshToken) { |
|
|
this.http.post(`${this.apiUrl}/refresh`, { refresh_token: refreshToken }).subscribe( |
|
|
(response: any) => { |
|
|
|
|
|
localStorage.setItem('access_token', response.access_token); |
|
|
|
|
|
|
|
|
const newAccessTokenExpiry = Date.now() + 2 * 60 * 1000; |
|
|
localStorage.setItem('access_token_expiry', newAccessTokenExpiry.toString()); |
|
|
|
|
|
|
|
|
}, |
|
|
error => { |
|
|
console.log("Error refreshing token", error); |
|
|
|
|
|
if ( |
|
|
error.status === 401 && |
|
|
(error.error.message === 'Refresh token has expired' || error.error.message === 'Invalid refresh token') |
|
|
) { |
|
|
|
|
|
|
|
|
|
|
|
this.removeToken(); |
|
|
this.loggedInSubject.next(false); |
|
|
window.location.href = '/authentication'; |
|
|
} else { |
|
|
|
|
|
console.error("Unexpected error:", error); |
|
|
} |
|
|
} |
|
|
); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|