Angular 8 auth guard - 确定用户是来自应用程序外部还是来自应用程序内部

Angular 8 auth guard - determine if user came from outside or from inside the app

似乎是个愚蠢的问题,但出于某种原因我想不出答案。

我有一个 auth guard,它检查存储在本地存储中的 JWT 令牌是否过期并抛出 "Your session has expired" 对话框,该对话框重定向用户登录 onClose。

在当前状态下,仅当浏览器在存储中有此令牌时才会抛出对话框;否则它会直接重定向到登录页面。

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
        if (!this._auth.isAuthenticated()) {
            if (this._auth.hasToken()) {
                this._dialogService.openErrorDialog('Your session has expired, please re-login', 0)
                    .afterClosed()
                    .subscribe(() => this.navigateToLogin(state.url));
            } else {
                this.navigateToLogin(state.url);
            }

            return false;
        }

    return true;
}

我想实现以下逻辑:当用户浏览某个应用页面时令牌过期 -> 用户导航到另一个页面 -> 抛出对话框 -> 重定向到登录;但是如果用户从 外部 导航到应用程序中的某个页面,它应该直接将他重定向到登录页面,而不抛出对话框,即使浏览器本地存储中已经有一个过期的令牌.

我尝试破解一些基于 的解决方案,但没有成功 - 虽然我可以 return 和来自 canActivate 函数的 Observable<boolean>,但我不能'我不知道如何让 rxjs mappairwise 的结果一起工作 - 所以我可以使用前一个 URL 的存在这一事实来确定用户来自哪里。

非常感谢任何帮助。

已创建 stackblitz sample for you. Used the info you shared in the 并创建如下服务。

@Injectable({ providedIn: "root" })
export class FirstVisitService {

  readonly isFirstVisit = new BehaviorSubject<boolean>(true);

  constructor(router: Router) {
    router.events
      .pipe(
        filter(event => event instanceof NavigationEnd),
        first()
      )
      .subscribe((e: NavigationEnd) => {
        this.isFirstVisit.next(false);
        this.isFirstVisit.complete();
      });
  }
}

并将其注入 auth.guard 并像这样使用:

constructor(private service: FirstVisitService   ) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {

    if (this.service.isFirstVisit.value) {
      console.log("first time");
    }  else{
      console.log("not first time");
    }

    return true;
  }

并且你必须在应用模块中导入它

export class AppModule {
  constructor(f : FirstVisitService) {}
}

因此它在任何事件发生之前发生并订阅路由器事件。

只需在 src/app/app.components.ts 中设置重定向即可。
这个 "component" 是 AppModule 被 boostrap 之后的第一个 boostrap。
所以只需将行放在那里,当用户来自外部时它总是会重定向。


// src/app/app.components.ts

import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss'],
})
export class AppComponent {
    constructor(private router: Router) {
       // no matter where the user is going
       // just redirect to login!
       // this will only run the first time the app bootstraps
       this.router.navigateByUrl('/login'); // <--------
    }
}