1

我有延迟加载和 onLoad Guard 的路线。在警卫中,我从后端获取导航菜单(您只会看到您经过身份验证的导航点)并将路线与来自后端的路线列表进行比较。

问题:当我单击路由的按钮时,会触发路由,但会立即取消(在控制台中跟踪),原因如下:

NavigationCancelingError: Cannot load children because the guard 
of the route "path: 'meldungsmanagement'" returned false

尽管调试角度显示 onLoad 方法甚至没有解决 - 它会返回 true!

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

AuthGuard 服务:

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 说他返回了 TRUE...

为什么路由器不等待警卫回答?“假”从何而来?我哪里做错了?

我会很感激任何帮助,谢谢!

PS:我已经阅读了问题Angular2: Router Event: NavigationCancel before Route Guard has resolve,但它与我的情况不匹配,因为用户仍然登录并且我不想在警卫内重定向。

4

1 回答 1

0

根据我的评论,这是一种返回您想要的值的方法:

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))
  );
}
于 2019-03-12T14:13:21.153 回答