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 map
与 pairwise
的结果一起工作 - 所以我可以使用前一个 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'); // <--------
}
}
似乎是个愚蠢的问题,但出于某种原因我想不出答案。
我有一个 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;
}
我想实现以下逻辑:当用户浏览某个应用页面时令牌过期 -> 用户导航到另一个页面 -> 抛出对话框 -> 重定向到登录;但是如果用户从 外部 导航到应用程序中的某个页面,它应该直接将他重定向到登录页面,而不抛出对话框,即使浏览器本地存储中已经有一个过期的令牌.
我尝试破解一些基于 Observable<boolean>
,但我不能'我不知道如何让 rxjs map
与 pairwise
的结果一起工作 - 所以我可以使用前一个 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'); // <--------
}
}