Reputation: 383
I am using sessionStorage to hold accessToken. My steps are as follows:-
Actually it is not logging me out from another tab.
I added below code but it is not working as expected.
@HostListener('window:storage', ['$event'])
onStorageChange(sv:StorageEvent) {
if(sv.storageArea == sessionStorage)
{
let token = sessionStorage.getItem('accessToken');
if(token == null || token == undefined)
this.router.navigate(['/login']);
}
}
Please let me know if I am doing any mistake. I am currently using this code in home page. Is it the right location?
Upvotes: 6
Views: 5732
Reputation: 431
Implement AuthGuard on your routes that require sign in. In the Auth Guard add your login check logic and if user is not logged in then redirect to sign in page.
auth.guard.ts
import { Injectable } from '@angular/core';
import {Router,CanActivate,ActivatedRouteSnapshot,RouterStateSnapshot}
from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
let token = sessionStorage.getItem('accessToken');
if(!token)
this.router.navigate(['/login']);
return false
}
return true;
}
}
Your Routing file
const routes: Routes = [
{
path: '',
component: YourComponent,
canActivate: [AuthGuard],
}]
I hope this works for you or anyone who's looking for the same solution. Thank you
Upvotes: 1
Reputation: 34445
To communicate between tabs, you can make use of localStorage
and still keep sessionStorage
to store your sensitive data.
Here is a small implementation of an authentication service which uses:
sessionStorage
to store your user data (token or whatever) localStorage
to communicate with other opened tabs.rxjs
to trigger events from the serviceThe idea is that your application listens for storage events. Then when you sign out, it sets a flag in localStorage
, which other opened tabs can capture.
import { Injectable } from "@angular/core";
import { Subject, Observable } from "rxjs";
@Injectable({providedIn:'root'})
export class AuthenticationService{
private eventSubject: Subject<boolean> = new Subject<boolean>();
public readonly statusChanged$: Observable<boolean> = this.eventSubject.asObservable();
private loggedIn = false;
constructor()
{
window.onstorage = () => { //
{
let loggedIn = sessionStorage.getItem('accessToken') !== null;
if(localStorage.getItem('signOut'))
{
loggedIn = false;
}
if(this.loggedIn !== loggedIn)//Don't trigger event if no change
{
this.loggedIn = loggedIn;
this.eventSubject.next(loggedIn);
}
};
}
}
public logIn()
{
//Do your business to login and obtain a token before here...
localStorage.removeItem('signOut');//clear flag in local storage
sessionStorage.setItem('accessToken', 'token');//save token in session storage
}
public logOut()
{
localStorage.setItem('signOut', 'true'); //trigger flag
sessionStorage.removeItem('accessToken'); //Remove token from session
}
public isLoggedIn()
{
return this.loggedIn;
}
}
You can just use that service in your components
constructor(private authSvc:AuthenticationService)
{
this.authSvc.statusChanged$.subscribe(isLoggedIn=>
{
//Do whatever you want
});
}
Here is a stackblitz demo.
Upvotes: 8
Reputation: 154
First of all you have to place this code in the app.component.ts file
secondly write a window event
window.addEventListener('storage', (event) => {
if (event.storageArea == localStorage) {
let token = localStorage.getItem('accessToken');
if (token == undefined) {
// Perform logout
//Navigate to login/home
this.router.navigate(['/login']);
}
}
});
I believe it should work fine
Upvotes: 1