Auto Login
Sampai sejauh ini, informasi user masih disimpan dalam memory. Jika aplikasi di reload, maka data user dan authentication akan hilang.
Untuk itu kita perlu menyimpan data kedalam local storage.
Buka file auth.service.ts, lalu tambahkan code pada method handleAuth dan autoLogin.(lihat code dengan bagian komentar).
Selain itu kita perlu mengganti tipe subject menjadi ReplaySubject.
import {Injectable} from '@angular/core'; import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import { Router } from '@angular/router'; import { catchError, tap } from 'rxjs/operators'; //import ReplaySUbject import { ReplaySubject, throwError } from 'rxjs'; import { User } from './user.model'; export interface AuthResponse { idToken: string; email: string; refreshToken: string; expiresIn: string; localId: string; registered?: boolean; } @Injectable({providedIn: 'root'}) export class AuthService { //ubah user subject menjadi ReplaySubject user = new ReplaySubject<User>(); token = ""; //inject router constructor(private http: HttpClient, private router : Router){} signUp(email: string, pswrd: string){ return this.http .post<AuthResponse>('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyAHq81IV8SqS_n6KL9wEmuB_qs3_8J4szU', { email: email, password: pswrd, returnSecureToken: true } ) .pipe(catchError(this.errHandling), tap(respData=>{ this.handleAuth(respData.email, respData.localId, respData.idToken, +respData.expiresIn); })); } login(email: string, pswrd: string){ return this.http .post<AuthResponse>('https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyAHq81IV8SqS_n6KL9wEmuB_qs3_8J4szU', { email: email, password: pswrd, returnSecureToken: true } ).pipe(catchError(this.errHandling), tap(respData=>{ this.handleAuth(respData.email, respData.localId, respData.idToken, +respData.expiresIn); })); } //method untuk autologin berdasarkan data localstorage autoLogin(){ const userData :{ email: string; id: string; _token: string; _tokenExpDt: string; } = JSON.parse(localStorage.getItem("userData") || '{}') ; if(!userData){ return; }else{ const loadUser = new User(userData.email, userData.id, userData._token, new Date(userData._tokenExpDt)); if(loadUser.token){ this.user.next(loadUser); this.token = userData._token; } } } logout(){ this.user.next(undefined); this.token = ""; this.router.navigate(['/auth']); } private handleAuth(email: string, userId: string, token: string, expiresIn: number){ const expDate = new Date(new Date().getTime()+ (expiresIn*1000)); const user = new User(email, userId, token, expDate); this.user.next(user); this.token = token; //menyimpan data ke localstorage localStorage.setItem('userData', JSON.stringify(user)); } private errHandling(errResp: HttpErrorResponse){ let errMsg = 'Unknown Error...'; if (!errResp.error || !errResp.error.error){ return throwError(errMsg); } switch(errResp.error.error.message){ case 'EMAIL_EXISTS': errMsg = 'Email sudah terdaftar'; break; case 'EMAIL_NOT_FOUND': errMsg = 'User belum terdaftar'; break; case 'INVALID_PASSWORD': errMsg = 'User atau Password salah'; break; } return throwError(errMsg); } }
Kemudian buka app.component.ts, implementasikan method ngOnInit untuk melakukan proses autoLogin.
import { Component, OnInit } from '@angular/core'; import { AuthService } from './auth/auth.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { constructor(private authSrv : AuthService){} ngOnInit(): void { this.authSrv.autoLogin(); } }
JIka Anda coba reload, aplikasi tetap dalam status authenticated.
Auto Logout
Berikutnya kita akan implementasikan autoLogout, karena token terdapat masa expires.
Buka file auth.service.ts, lalu ubah menjadi code seperti dibawah
import {Injectable} from '@angular/core'; import {HttpClient, HttpErrorResponse} from '@angular/common/http'; import { Router } from '@angular/router'; import { catchError, tap } from 'rxjs/operators'; import { ReplaySubject, throwError } from 'rxjs'; import { User } from './user.model'; export interface AuthResponse { idToken: string; email: string; refreshToken: string; expiresIn: string; localId: string; registered?: boolean; } @Injectable({providedIn: 'root'}) export class AuthService { user = new ReplaySubject<User>(); token = ""; private tokenExpTimer : any; constructor(private http: HttpClient, private router : Router){} signUp(email: string, pswrd: string){ return this.http .post<AuthResponse>('https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=AIzaSyAHq81IV8SqS_n6KL9wEmuB_qs3_8J4szU', { email: email, password: pswrd, returnSecureToken: true } ) .pipe(catchError(this.errHandling), tap(respData=>{ this.handleAuth(respData.email, respData.localId, respData.idToken, +respData.expiresIn); })); } login(email: string, pswrd: string){ return this.http .post<AuthResponse>('https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=AIzaSyAHq81IV8SqS_n6KL9wEmuB_qs3_8J4szU', { email: email, password: pswrd, returnSecureToken: true } ).pipe(catchError(this.errHandling), tap(respData=>{ this.handleAuth(respData.email, respData.localId, respData.idToken, +respData.expiresIn); })); } autoLogin(){ const userData :{ email: string; id: string; _token: string; _tokenExpDt: string; } = JSON.parse(localStorage.getItem("userData") || '{}') ; if(!userData){ return; }else{ const loadUser = new User(userData.email, userData.id, userData._token, new Date(userData._tokenExpDt)); if(loadUser.token){ this.user.next(loadUser); this.token = userData._token; //lakukan perhitungan delta dari expired date dengan current date dalam ms. const expDur = new Date(userData._tokenExpDt).getTime() - new Date().getTime(); this.autoLogout(expDur); } } } //method untuk autologout ketika token expired autoLogout(expDuration : number){ this.tokenExpTimer = setTimeout(()=>{ this.logout(); }, expDuration); } logout(){ this.user.next(undefined); this.token = ""; this.router.navigate(['/auth']); //hapus data local storage dan setup autologout localStorage.removeItem('userData'); if(this.tokenExpTimer){ clearTimeout(this.tokenExpTimer); } this.tokenExpTimer = null; } private handleAuth(email: string, userId: string, token: string, expiresIn: number){ const expDate = new Date(new Date().getTime()+ (expiresIn*1000)); const user = new User(email, userId, token, expDate); this.user.next(user); //tambahkan autologout this.autoLogout(expiresIn * 1000); this.token = token; localStorage.setItem('userData', JSON.stringify(user)); } private errHandling(errResp: HttpErrorResponse){ let errMsg = 'Unknown Error...'; if (!errResp.error || !errResp.error.error){ return throwError(errMsg); } switch(errResp.error.error.message){ case 'EMAIL_EXISTS': errMsg = 'Email sudah terdaftar'; break; case 'EMAIL_NOT_FOUND': errMsg = 'User belum terdaftar'; break; case 'INVALID_PASSWORD': errMsg = 'User atau Password salah'; break; } return throwError(errMsg); } }