简体   繁体   English

组件在保护后不呈现,角度为 9

[英]Components doesn't render after guard, angular 9

I'm trying to protect authenticated routes using AuthGuard middleware.我正在尝试使用AuthGuard中间件保护经过身份验证的路由。 When I implement this middleware into a route.当我将此中间件实现到路由中时。 Those routes doesn't work after I activate guard.我激活守卫后这些路线不起作用。

App routing module应用路由模块

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]
})

and AuthGuardMiddleware和 AuthGuard 中间件

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

How can I fix it ?我该如何解决? Note: AuthService::user type is BehaviorSubject initialized as null注意:AuthService::user 类型是 BehaviorSubject 初始化为 null

UPDATE更新

I realized that when I clean up my app component and remove conditional router outlet, everything start to work fine.我意识到当我清理我的应用程序组件并删除条件路由器插座时,一切都开始正常工作。 I still don't know what exactly causing this error.我仍然不知道究竟是什么导致了这个错误。

app component应用组件

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

app component view应用组件视图

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

Your AuthService.user returns an Observable stream and it never completes.您的AuthService.user返回一个 Observable 流并且它永远不会完成。 As far as I know, the canLoad and canActivate need a completed Observable .据我所知, canLoadcanActivate需要一个完整的Observable You can make it so by using the take(1) operator:您可以使用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)
    );
  }

I guess another reason this can happen, is because you are using the PreloadAllModules strategy.我想这可能发生的另一个原因是因为您正在使用PreloadAllModules策略。 This will load all modules immediately, but I guess this is done when the user is not logged in yet and therefore the guard will return false and the module won't load, and won't be retried.这将立即加载所有模块,但我想这是在用户尚未登录时完成的,因此守卫将返回 false 并且模块不会加载,也不会重试。

So you need to rethink if you want to use the canLoad guard this way, if you are using the PreloadAllModules .因此,如果您使用PreloadAllModules ,您需要重新考虑是否要以这种方式使用canLoad保护。 Perhaps the canActivate guard will be enough.也许canActivate守卫就足够了。

You can also implement a custom preload strategy, which somehow waits for the user to login to load it您还可以实现自定义预加载策略,以某种方式等待用户登录加载它


With your additional information about the conditional router-outlet, it makes sense, because first the component will be placed in one router-outlet , but after the routing is completed, the other router-outlet becomes visible, but nothing has been placed in there :).有了关于条件路由器插座的附加信息,这是有道理的,因为首先组件将放置在一个router-outlet ,但是在路由完成后,另一个router-outlet变得可见,但没有放置任何东西在那里:)。 You can update your template by utilizing the ngTemplateOutlet directive to circumvent this:你可以通过使用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>

This way you make sure that only one router-outlet is placed in the AppComponent , which is the way it should be done通过这种方式,您可以确保AppComponent中只放置一个router-outlet ,这是应该完成的方式

I can't see where you use AuthGuard in your AppRoutingModule.我看不到您在 AppRoutingModule 中使用 AuthGuard 的位置。

Try to apply it to any route, eg:尝试将其应用于任何路线,例如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM