角度为9的后卫后组件不渲染

时间:2020-03-30 10:24:49

标签: angular

我正在尝试使用AuthGuard中间件来保护经过身份验证的路由。当我将此中间件实现为路由时。在我激活后卫后,这些路线将失效。

应用程序路由模块

const routes: Routes = [
  {
    path: 'posts',
    canLoad: [AuthGuardMiddleware],
    loadChildren: () => import('./modules/posts/posts.module').then(m => m.PostsModule)
  },
  {
    path: 'users',
    canLoad: [AuthGuardMiddleware],
    loadChildren: () => import('./modules/users/users.module').then(m => m.UsersModule)
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, {
    preloadingStrategy: PreloadAllModules
  })],
  exports: [RouterModule]
})

和AuthGuardMiddleware

@Injectable({
  providedIn: 'root'
})
export class AuthGuardMiddleware implements CanActivate, CanLoad {
  constructor(private authService: AuthService, private router: Router) {
  }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> {
    return this.authService.user.pipe(map(user => {
      if (user) {
        return true;
      }
      return this.router.createUrlTree(['/login']);
    }));
  }

  canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
    return this.authService.user.pipe(map(user => {
      if (user) {
        return true;
      }
      this.router.navigate(['/']);
      return false;
    }));
  }
}

我该如何解决? 注意:AuthService ::用户类型为BehaviorSubject,初始化为null

更新

我意识到,当我清理我的应用程序组件并删除有条件的路由器插座时,一切都开始正常工作。我仍然不知道是什么导致了此错误。

应用程序组件

export class AppComponent implements OnInit {
  currentUrl: string;
  isAuthRoute = false;

  constructor(private router: Router) {
  }

  ngOnInit() {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        this.currentUrl = event.url;
        this.isAuthRoute = ['/login', '/register']
          .indexOf(this.currentUrl) !== -1;
      }
    });
  }
}

应用程序组件视图

<div *ngIf="!isAuthRoute">
  <div class="row page-wrapper">
    <div class="col-md-3 col-md-pull-9">
      <app-sidebar></app-sidebar>
    </div>
    <div class="col-md-9 col-md-push-3 content-area">
      <router-outlet></router-outlet>
    </div>
  </div>
</div>

<div style="height: 80vh" class="d-flex justify-content-center align-items-center" *ngIf="isAuthRoute">
  <router-outlet ></router-outlet>
</div>

2 个答案:

答案 0 :(得分:1)

您的AuthService.user返回一个Observable流,但它永远不会完成。据我所知,canLoadcanActivate需要完整的Observable。您可以使用take(1)运算符来做到这一点:

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> {
    return this.authService.user.pipe(
       map(user => {
        if (user) {
          return true;
        }
        return this.router.createUrlTree(['/login']);
      }),
      take(1)
    );
  }

  canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
    return this.authService.user.pipe(
      map(user => {
        if (user) {
          return true;
        }
        this.router.navigate(['/']);
        return false;
      }),
      take(1)
    );
  }

我猜这可能发生的另一个原因是,因为您使用的是PreloadAllModules策略。这将立即加载所有模块,但是我猜这是在用户尚未登录时完成的,因此防护措施将返回false,模块将不会加载,也不会重试。

因此,如果您要使用canLoad,则需要重新考虑是否要使用PreloadAllModules保护。也许canActivate警卫就足够了。

您还可以实现自定义的预加载策略,该策略以某种方式等待用户登录以加载它


有了有关条件路由器出口的其他信息,这很有意义,因为首先将组件放置在一个router-outlet中,但是在完成路由之后,另一个router-outlet将变得可见,但没有放置任何东西:)。您可以利用ngTemplateOutlet指令来规避此问题,从而更新模板:

<ng-template #outlet>
  <router-outlet ></router-outlet>
</ng-template>

<div *ngIf="!isAuthRoute">
  <div class="row page-wrapper">
    <div class="col-md-3 col-md-pull-9">
      <app-sidebar></app-sidebar>
    </div>
    <div class="col-md-9 col-md-push-3 content-area">
      <ng-component [ngTemplateOutlet]="outlet"></ng-component>
    </div>
  </div>
</div>

<div style="height: 80vh" class="d-flex justify-content-center align-items-center" *ngIf="isAuthRoute">
  <ng-component [ngTemplateOutlet]="outlet"></ng-component>
</div>

这样,您可以确保在router-outlet中仅放置一个AppComponent,这是应该这样做的方式

答案 1 :(得分:0)

我看不到您在AppRoutingModule中使用AuthGuard的地方。

尝试将其应用于任何路线,例如:

{
    path: 'posts',
    canLoad: [AuthGuard],
    loadChildren: () => import('./modules/posts/posts.module').then(m => m.PostsModule),
},