Angular 11实现单标签页登出时所有标签页同步登出(Cookie存Token)
Angular 11 多标签页同步登出实现方案
由于Cookie的变更不会触发浏览器的storage事件,我们需要结合localStorage传递登出信号,配合Cookie清理逻辑实现多标签页同步登出,具体实现步骤如下:
1. 改造登出逻辑
在登出方法中,除了清除Token对应的Cookie,还要在localStorage中写入一个登出标识,触发其他标签页的storage事件:
// auth.service.ts import { Injectable } from '@angular/core'; import { CookieService } from 'ngx-cookie-service'; // 假设使用ngx-cookie-service操作Cookie @Injectable({ providedIn: 'root' }) export class AuthService { constructor(private cookieService: CookieService) {} logout(): void { // 清除Token Cookie(注意path/domain要和设置时一致) this.cookieService.delete('token', '/'); // 写入登出触发信号,触发跨标签页storage事件 localStorage.setItem('app-logout-trigger', Date.now().toString()); // 立即移除标记,避免残留影响后续操作 setTimeout(() => localStorage.removeItem('app-logout-trigger'), 100); // 当前标签页跳转到登录页 window.location.href = '/login'; } }
2. 全局监听Storage事件
通过根组件或全局服务监听storage事件,检测到登出信号时执行本地登出逻辑:
方式一:根组件中直接监听
// app.component.ts import { Component, HostListener, OnDestroy } from '@angular/core'; import { CookieService } from 'ngx-cookie-service'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnDestroy { constructor(private cookieService: CookieService) {} @HostListener('window:storage', ['$event']) onStorageChange(event: StorageEvent): void { // 检测是否是我们定义的登出触发信号 if (event.key === 'app-logout-trigger') { this.handleCrossTabLogout(); } } private handleCrossTabLogout(): void { // 清除当前标签页的Token Cookie if (this.cookieService.check('token')) { this.cookieService.delete('token', '/'); } // 避免重复跳转,仅当前不在登录页时跳转 if (window.location.pathname !== '/login') { window.location.href = '/login'; } } ngOnDestroy(): void { // HostListener会自动移除监听,无需手动处理 } }
方式二:全局服务监听
如果需要更灵活的逻辑拆分,可以创建全局服务:
// cross-tab-logout.service.ts import { Injectable, OnDestroy } from '@angular/core'; import { CookieService } from 'ngx-cookie-service'; @Injectable({ providedIn: 'root' }) export class CrossTabLogoutService implements OnDestroy { private storageListener: EventListener; constructor(private cookieService: CookieService) { this.storageListener = (event: StorageEvent) => { if (event.key === 'app-logout-trigger') { this.handleLogout(); } }; window.addEventListener('storage', this.storageListener); } private handleLogout(): void { if (this.cookieService.check('token')) { this.cookieService.delete('token', '/'); } if (window.location.pathname !== '/login') { window.location.href = '/login'; } } ngOnDestroy(): void { // 组件销毁时移除监听,避免内存泄漏 window.removeEventListener('storage', this.storageListener); } }
然后在根组件中注入该服务,确保监听全局生效:
// app.component.ts import { Component } from '@angular/core'; import { CrossTabLogoutService } from './cross-tab-logout.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { constructor(private crossTabLogoutService: CrossTabLogoutService) {} }
3. 关键注意事项
storage事件仅在同源的其他标签页触发,当前触发变更的标签页不会收到事件,所以当前标签页的登出逻辑需要直接执行- 建议给
localStorage的key加项目前缀,避免和其他业务逻辑冲突 - 清理Cookie时要保证
path和domain参数与设置时一致,否则无法正确清除 - 若使用
sessionStorage替代localStorage,则仅在同一会话的标签页中生效,可根据业务需求选择
内容的提问来源于stack exchange,提问作者mallikharjuna
相关产品推荐
相关产品推荐

