【问题标题】:Log out issue from second tab when log out from first tab in Angular从Angular中的第一个选项卡注销时从第二个选项卡注销问题
【发布时间】:2022-02-23 17:03:42
【问题描述】:

我正在使用 sessionStorage 来保存 accessToken。我的步骤如下:-

  • 登录网站
  • 单击选项卡的重复选项。它将在第二个标签中显示该网站。
  • 从第一个选项卡注销。
  • 当我刷新/点击第二个选项卡上的任何操作时,期望从另一个选项卡注销。

实际上,它并没有将我从另一个选项卡中注销。

我添加了下面的代码,但它没有按预期工作。

@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']);
      }
    }

如果我做错了,请告诉我。 我目前在主页中使用此代码。位置合适吗?

【问题讨论】:

    标签: angular authentication access-token session-storage


    【解决方案1】:

    要在标签之间进行通信,您可以使用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

    【讨论】:

    • 感谢您让我知道保留标志以跟踪登录和注销事件。真的很好用。
    • 很高兴我能帮上忙
    【解决方案2】:

    首先你必须把这段代码放在 app.component.ts 文件中

    其次写一个窗口事件

     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']);
                    }
                }
            });
    

    我相信它应该可以正常工作

    【讨论】:

    • 我在 app.component.ts 文件的 ngOnInit() 中添加了上面的代码。当我从第一个选项卡注销时,这个函数永远不会被调用。
    • @simpleuser 你如何在 localStorage 中设置令牌并检查一下,我将相应地编辑上面的代码。
    • 你能帮我处理一下 sessionStorage 吗?会话存储有助于在浏览器自动关闭时自动注销。
    • @simpleuser sessionStorage 的问题是它不会清除其他选项卡的记录,它只会清除您退出的选项卡上的记录,而在 localStorage 它适用于所有标签。因此,如果您担心在关闭浏览器时清除本地存储,您可以使用 window.unload 事件简单地卸载页面。这是示例代码:window.onunload = () =&gt; { // Clear the local storage window.localStorage.clear() }
    • 您是否想说“window.addEventListener('storage')”仅适用于 localStorage。我问这个是因为当我在函数启动之后放置 console.log("Hello") 时,它也没有打印任何东西。我的问题是什么时候应该调用这个函数?
    【解决方案3】:

    在需要登录的路由上实施 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],
    }]
    

    我希望这对您或正在寻找相同解决方案的任何人都有效。谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      相关资源
      最近更新 更多