Angular 从第一个选项卡注销时从第二个选项卡注销问题
Log out issue from second tab when log out from first tab in Angular
我正在使用 sessionStorage 来保存 accessToken。我的步骤如下:-
- 登录网站
- 单击选项卡的复制选项。它将在第二个选项卡中显示该网站。
- 从第一个选项卡注销。
- 当我 refresh/hit 在第二个选项卡上执行任何操作时,期望从另一个选项卡注销。
实际上它并没有让我从另一个选项卡中注销。
我添加了以下代码,但它没有按预期工作。
@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']);
}
}
如果我做错了,请告诉我。
我目前在主页中使用此代码。位置对吗?
首先,您必须将此代码放入 app.component.ts 文件
其次写一个window事件
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']);
}
}
});
我相信它应该可以正常工作
要在选项卡之间进行通信,您可以使用 localStorage
并仍然保留 sessionStorage
来存储您的敏感数据。
这是身份验证服务的一个小实现,它使用:
sessionStorage
存储您的用户数据(令牌或其他)
localStorage
与其他打开的标签进行通信。
rxjs
从服务触发事件
想法是您的应用程序侦听存储事件。然后,当您注销时,它会在 localStorage
中设置一个标志,其他打开的选项卡可以捕获该标志。
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;
}
}
您可以只在您的组件中使用该服务
constructor(private authSvc:AuthenticationService)
{
this.authSvc.statusChanged$.subscribe(isLoggedIn=>
{
//Do whatever you want
});
}
这里是stackblitz demo。
在需要登录的路由上实施 AuthGuard。在 Auth Guard 中添加您的登录检查逻辑,如果用户未登录则重定向到登录页面。
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;
}
}
你的路由文件
const routes: Routes = [
{
path: '',
component: YourComponent,
canActivate: [AuthGuard],
}]
我希望这对您或任何正在寻找相同解决方案的人有用。谢谢
我正在使用 sessionStorage 来保存 accessToken。我的步骤如下:-
- 登录网站
- 单击选项卡的复制选项。它将在第二个选项卡中显示该网站。
- 从第一个选项卡注销。
- 当我 refresh/hit 在第二个选项卡上执行任何操作时,期望从另一个选项卡注销。
实际上它并没有让我从另一个选项卡中注销。
我添加了以下代码,但它没有按预期工作。
@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']);
}
}
如果我做错了,请告诉我。 我目前在主页中使用此代码。位置对吗?
首先,您必须将此代码放入 app.component.ts 文件
其次写一个window事件
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']);
}
}
});
我相信它应该可以正常工作
要在选项卡之间进行通信,您可以使用 localStorage
并仍然保留 sessionStorage
来存储您的敏感数据。
这是身份验证服务的一个小实现,它使用:
sessionStorage
存储您的用户数据(令牌或其他)localStorage
与其他打开的标签进行通信。rxjs
从服务触发事件
想法是您的应用程序侦听存储事件。然后,当您注销时,它会在 localStorage
中设置一个标志,其他打开的选项卡可以捕获该标志。
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;
}
}
您可以只在您的组件中使用该服务
constructor(private authSvc:AuthenticationService)
{
this.authSvc.statusChanged$.subscribe(isLoggedIn=>
{
//Do whatever you want
});
}
这里是stackblitz demo。
在需要登录的路由上实施 AuthGuard。在 Auth Guard 中添加您的登录检查逻辑,如果用户未登录则重定向到登录页面。
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;
}
}
你的路由文件
const routes: Routes = [
{
path: '',
component: YourComponent,
canActivate: [AuthGuard],
}]
我希望这对您或任何正在寻找相同解决方案的人有用。谢谢