Angular 6 - NavigationCancel - 原因:"guard of the route returned false" - 在守卫完成之前
Angular 6 - NavigationCancel - reason: "guard of the route returned false" - before guard even finished
我有延迟加载和 onLoad Guard 的路由。在守卫中,我从后端抓取导航菜单(你只能看到你经过身份验证的导航点)并将路线与来自后端的路线列表进行比较。
问题:
当我点击路由按钮时,路由被触发,但立即被取消(在控制台中跟踪),原因如下:
NavigationCancelingError: Cannot load children because the guard
of the route "path: 'meldungsmanagement'" returned false
尽管调试 angular 显示 onLoad 方法甚至没有解析 - 它会 return 正确!
appRouting.module.ts
import {NgModule} from '@angular/core';
import {PortalComponent} from './portal/portal.component';
import {AuthGuardService} from './core/authguard.service';
import {RouterModule, Routes} from '@angular/router';
const appRoutes: Routes = [
{
path: '',
redirectTo: 'startseite',
pathMatch: 'full'
},
{
path: 'startseite',
component: PortalComponent
},
{
path: 'meldungsmanagement',
loadChildren: './incidents/incidentOverview.module#IncidentOverviewModule',
canLoad: [AuthGuardService]
},
];
@NgModule({
imports: [RouterModule.forRoot(
appRoutes,
{enableTracing: true})], // enable only for debugging purposes
exports: [RouterModule]
})
export class AppRoutingModule {
}
AuthGuardService:
import {Injectable} from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
CanLoad,
Route,
Router,
RouterStateSnapshot,
UrlSegment
} from '@angular/router';
import {GlobalSettingsService} from './globalSettings.service';
import {Observable} from 'rxjs';
import {NavbarService} from './navbar.service';
import {NavbarModel} from '../shared/models/navbar.model';
import {KeycloakService} from './keycloak/keycloak.service';
@Injectable()
export class AuthGuardService implements CanActivate, CanLoad {
constructor(private router: Router,
private keycloakService: KeycloakService,
private navBarService: NavbarService,
private globalSettings: GlobalSettingsService) {
}
canLoad(route: Route,
segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
const isLoggedIn = this.keycloakService.isAuthenticated();
if (isLoggedIn) {
this.navBarService.getStucture().subscribe(menuRoutes => {
const isAccessAllowed: boolean = this.checkRoleAccessAllowed(segments, menuRoutes);
console.log('AuthGuard.canLoad() - return ' + isAccessAllowed + ' for route ' + route.path);
return Promise.resolve(isAccessAllowed);
}
);
} else {
console.log('AuthGuard.canLoad() - return false (not loggedIn) for route ' + route.path);
return Promise.resolve(false);
}
}
checkRoleAccessAllowed(url: UrlSegment[], menu: Array<NavbarModel>): boolean {
const foundNavbarModel: NavbarModel = menu.find(value => value.link.indexOf(url[0].path) > -1);
if (foundNavbarModel) {
return true;
} else {
return false;
}
}
}
控制台输出:
(从点击按钮追踪到路由 "meldungsmanagement" 上)
Router Event: NavigationStart
NavigationStart(id: 3, url: '/meldungsmanagement')
NavigationStart {id: 3, url: "/meldungsmanagement", navigationTrigger: "imperative", restoredState: null}
Router Event: NavigationCancel
NavigationCancel(id: 3, url: '/meldungsmanagement')
NavigationCancel {id: 3, url: "/meldungsmanagement", reason: "NavigationCancelingError: Cannot load children bec…route "path: 'meldungsmanagement'" returned false"}id: 3reason: "NavigationCancelingError: Cannot load children because the guard of the route "path: 'meldungsmanagement'" returned false"url: "/meldungsmanagement"__proto__: RouterEvent
Router Event: NavigationStart
NavigationStart(id: 4, url: '/')
NavigationStart {id: 4, url: "/", navigationTrigger: "imperative", restoredState: null}
Router Event: RoutesRecognized
Router Event: GuardsCheckStart
Router Event: GuardsCheckEnd
Router Event: ActivationEnd
Router Event: ChildActivationEnd
Router Event: NavigationEnd
Router Event: Scroll
Router Event: NavigationStart
NavigationStart(id: 5, url: '/')
NavigationStart {id: 5, url: "/", navigationTrigger: "imperative", restoredState: null}
AuthGuard.canLoad() - return true for route meldungsmanagement
Router Event: RoutesRecognized
RoutesRecognized(id: 5, url: '/', urlAfterRedirects: '/startseite', state: Route(url:'', path:'') { Route(url:'startseite', path:'startseite') } )
RoutesRecognized {id: 5, url: "/", urlAfterRedirects: "/startseite", state: RouterStateSnapshot}
Router Event: GuardsCheckStart
GuardsCheckStart(id: 5, url: '/', urlAfterRedirects: '/startseite', state: Route(url:'', path:'') { Route(url:'startseite', path:'startseite') } )
GuardsCheckStart {id: 5, url: "/", urlAfterRedirects: "/startseite", state: RouterStateSnapshot}
Router Event: ChildActivationStart
ChildActivationStart(path: '')
如您所见,路由被触发、关闭、重定向到“/”,许多行之后 authGuard 说他 returnd TRUE...
路由器到底为什么不等待警卫回答? "false" 从哪里来?我哪里错了?
非常感谢任何帮助,谢谢!
PS: 我已经阅读了问题 但它与我的情况不符,因为用户仍然登录并且我不想在守卫内重定向。
根据我的评论,这是一种返回您想要的值的方法:
if (isLoggedIn) {
return this.navBarService.getStucture().pipe(
map(menuRoutes => this.checkRoleAccessAllowed(segments, menuRoutes)),
tap(value => console.log('AuthGuard.canLoad() - return ' + value + ' for route ' + route.path))
);
}
我有延迟加载和 onLoad Guard 的路由。在守卫中,我从后端抓取导航菜单(你只能看到你经过身份验证的导航点)并将路线与来自后端的路线列表进行比较。
问题: 当我点击路由按钮时,路由被触发,但立即被取消(在控制台中跟踪),原因如下:
NavigationCancelingError: Cannot load children because the guard
of the route "path: 'meldungsmanagement'" returned false
尽管调试 angular 显示 onLoad 方法甚至没有解析 - 它会 return 正确!
appRouting.module.ts
import {NgModule} from '@angular/core';
import {PortalComponent} from './portal/portal.component';
import {AuthGuardService} from './core/authguard.service';
import {RouterModule, Routes} from '@angular/router';
const appRoutes: Routes = [
{
path: '',
redirectTo: 'startseite',
pathMatch: 'full'
},
{
path: 'startseite',
component: PortalComponent
},
{
path: 'meldungsmanagement',
loadChildren: './incidents/incidentOverview.module#IncidentOverviewModule',
canLoad: [AuthGuardService]
},
];
@NgModule({
imports: [RouterModule.forRoot(
appRoutes,
{enableTracing: true})], // enable only for debugging purposes
exports: [RouterModule]
})
export class AppRoutingModule {
}
AuthGuardService:
import {Injectable} from '@angular/core';
import {
ActivatedRouteSnapshot,
CanActivate,
CanLoad,
Route,
Router,
RouterStateSnapshot,
UrlSegment
} from '@angular/router';
import {GlobalSettingsService} from './globalSettings.service';
import {Observable} from 'rxjs';
import {NavbarService} from './navbar.service';
import {NavbarModel} from '../shared/models/navbar.model';
import {KeycloakService} from './keycloak/keycloak.service';
@Injectable()
export class AuthGuardService implements CanActivate, CanLoad {
constructor(private router: Router,
private keycloakService: KeycloakService,
private navBarService: NavbarService,
private globalSettings: GlobalSettingsService) {
}
canLoad(route: Route,
segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
const isLoggedIn = this.keycloakService.isAuthenticated();
if (isLoggedIn) {
this.navBarService.getStucture().subscribe(menuRoutes => {
const isAccessAllowed: boolean = this.checkRoleAccessAllowed(segments, menuRoutes);
console.log('AuthGuard.canLoad() - return ' + isAccessAllowed + ' for route ' + route.path);
return Promise.resolve(isAccessAllowed);
}
);
} else {
console.log('AuthGuard.canLoad() - return false (not loggedIn) for route ' + route.path);
return Promise.resolve(false);
}
}
checkRoleAccessAllowed(url: UrlSegment[], menu: Array<NavbarModel>): boolean {
const foundNavbarModel: NavbarModel = menu.find(value => value.link.indexOf(url[0].path) > -1);
if (foundNavbarModel) {
return true;
} else {
return false;
}
}
}
控制台输出: (从点击按钮追踪到路由 "meldungsmanagement" 上)
Router Event: NavigationStart
NavigationStart(id: 3, url: '/meldungsmanagement')
NavigationStart {id: 3, url: "/meldungsmanagement", navigationTrigger: "imperative", restoredState: null}
Router Event: NavigationCancel
NavigationCancel(id: 3, url: '/meldungsmanagement')
NavigationCancel {id: 3, url: "/meldungsmanagement", reason: "NavigationCancelingError: Cannot load children bec…route "path: 'meldungsmanagement'" returned false"}id: 3reason: "NavigationCancelingError: Cannot load children because the guard of the route "path: 'meldungsmanagement'" returned false"url: "/meldungsmanagement"__proto__: RouterEvent
Router Event: NavigationStart
NavigationStart(id: 4, url: '/')
NavigationStart {id: 4, url: "/", navigationTrigger: "imperative", restoredState: null}
Router Event: RoutesRecognized
Router Event: GuardsCheckStart
Router Event: GuardsCheckEnd
Router Event: ActivationEnd
Router Event: ChildActivationEnd
Router Event: NavigationEnd
Router Event: Scroll
Router Event: NavigationStart
NavigationStart(id: 5, url: '/')
NavigationStart {id: 5, url: "/", navigationTrigger: "imperative", restoredState: null}
AuthGuard.canLoad() - return true for route meldungsmanagement
Router Event: RoutesRecognized
RoutesRecognized(id: 5, url: '/', urlAfterRedirects: '/startseite', state: Route(url:'', path:'') { Route(url:'startseite', path:'startseite') } )
RoutesRecognized {id: 5, url: "/", urlAfterRedirects: "/startseite", state: RouterStateSnapshot}
Router Event: GuardsCheckStart
GuardsCheckStart(id: 5, url: '/', urlAfterRedirects: '/startseite', state: Route(url:'', path:'') { Route(url:'startseite', path:'startseite') } )
GuardsCheckStart {id: 5, url: "/", urlAfterRedirects: "/startseite", state: RouterStateSnapshot}
Router Event: ChildActivationStart
ChildActivationStart(path: '')
如您所见,路由被触发、关闭、重定向到“/”,许多行之后 authGuard 说他 returnd TRUE...
路由器到底为什么不等待警卫回答? "false" 从哪里来?我哪里错了?
非常感谢任何帮助,谢谢!
PS: 我已经阅读了问题
根据我的评论,这是一种返回您想要的值的方法:
if (isLoggedIn) {
return this.navBarService.getStucture().pipe(
map(menuRoutes => this.checkRoleAccessAllowed(segments, menuRoutes)),
tap(value => console.log('AuthGuard.canLoad() - return ' + value + ' for route ' + route.path))
);
}