Angular 8 auth guard - определяет, пришел ли пользователь извне или изнутри приложения

Кажется, глупый вопрос, но я почему-то не могу понять ответа.

У меня есть защита аутентификации, которая проверяет истечение срока действия токена JWT, хранящегося в локальном хранилище, и выдает диалоговое окно «Срок действия вашего сеанса истек», который перенаправляет пользователя на вход 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;
}

Я хочу реализовать следующую логику: срок действия токена истек, когда пользователь просматривал какую-то страницу приложения -> пользователь перешел на другую страницу -> диалоговое окно запущено -> перенаправление для входа в систему; но если пользователь переходит на какую-либо страницу в приложении из извне, он должен перенаправить его прямо на страницу входа, без вывода диалогового окна, даже если в локальном хранилище браузера уже есть просроченный токен.

Я пытался взломать некоторые решения, основанные на this, но это не сработало - хотя я могу вернуть Observable<boolean> из функции canActivate я не мог понять, как заставить rxjs map работать с результатами pairwise, поэтому я мог использовать факт существования предыдущего URL-адреса, чтобы определить, откуда пришел пользователь.

Любая помощь очень ценится.


person grreeenn    schedule 26.11.2019    source источник
comment
пользователь переходит на какую-либо страницу в приложении извне - вы имеете в виду, что вы хотите определять, когда пользователь перешел по глубокой ссылке, чтобы перейти на страницу вашего веб-сайта?   -  person Sergey Rudenko    schedule 26.11.2019
comment
но если пользователь переходит на какую-либо страницу в приложении извне, он должен перенаправить его прямо на страницу входа - поместите эту логику на app.component или в другое место, которое пользователь инициализирует один раз при входе в ваше приложение.   -  person Stavm    schedule 26.11.2019


Ответы (2)


Создан образец stackblitz для вас. Использовали информацию, которой вы поделились в ссылке и создал сервис, как показано ниже.

@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) {}
}

Таким образом, он имеет место и подписывает событие маршрутизатора до того, как произошло какое-либо событие.

person Eldar    schedule 26.11.2019

Просто установите перенаправление в src/app/app.components.ts.
Этот «компонент» является первым, который активизируется после того, как AppModule был активирован.
Так что просто перетащите туда строку, и он всегда будет перенаправлять, когда пользователь приходит извне.


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

person guillefd    schedule 27.11.2019
comment
это не то, что я хочу. Если у пользователя есть действующий токен, его не следует перенаправлять для входа в систему. Хотя я могу внедрить службу аутентификации в AppComponent и реализовать эту логику, мне больше нравится решение Эльдара, поскольку оно не смешивает логику компонента и логику защиты. В любом случае, спасибо :) - person grreeenn; 27.11.2019