簡體   English   中英

Angular:在每次路線更改時運行 canActivate

[英]Angular: Run canActivate on each route change

我最近被 Angular 路由守衛困住了。 CanActive 僅在頁面加載時運行一次,並且不會在受保護路由內的路由更改時運行。 我認為這已更改,因為它曾經在每次更改時運行。 從我在論壇上讀到的內容來看,我應該使用 CanActivateChild。 問題是,我們的應用程序由幾個模塊組成,這些模塊有幾個路由后代,當我在根模塊中使用 CanActivateChild 時,在更改路由時會多次調用它。

我發現為每個孩子分配一個守衛很愚蠢,因為對於 AppModule,那些延遲加載的子模塊應該只是“黑匣子”,我想定義所有這些模塊都應該受到保護。

export const routes: Routes = [
  {
    path: '404',
    component: NotFoundComponent
  },
  {
    path: '',
    canActivate: [AuthGuard],
    component: FullLayoutComponent,
    data: {
      title: 'Home'
    },
    children: [
      {
        path: 'administration',
        loadChildren: './administration/administration.module#AdministrationModule'
      },
      {
        path: 'settings',
        loadChildren: './settings/settings.module#SettingsModule'
      }
    ]
  },
  {
    path: '',
    loadChildren: './account/account.module#AccountModule'
  },
  {
    path: '**',
    redirectTo: '404'
  }
];

有什么解決辦法嗎? 或者您認為這在安全方面“不是問題”?

謝謝大家。

面對同樣的問題,我能在這個問題上找到的只是 Github 上的幾個已解決的問題,Angular devs 聲明這種行為“是設計使然”。

所以我最終做的是訂閱 app.component 中的導航事件並在那里觸發 AuthGuard 檢查:

constructor(
  private router: Router,
  private route: ActivatedRoute,
  private authGuard: AuthGuard,
) {}

ngOnInit() {
  this.router.events
    .subscribe(event => {
      if (event instanceof RoutesRecognized) {
        this.guardRoute(event);
      }
    }));
}

private guardRoute(event: RoutesRecognized): void {
  if (this.isPublic(event)) {
    return;
  }

  if (!this.callCanActivate(event, this.authGuard)) {
    return;
  }
}

private callCanActivate(event: RoutesRecognized, guard: CanActivate) {
  return guard.canActivate(this.route.snapshot, event.state);
}

private isPublic(event: RoutesRecognized) {
  return event.state.root.firstChild.data.isPublic;
}

AuthGuard 是相當標准的:

@Injectable()
export class AuthGuard implements CanActivate{

  constructor(private auth: AuthService, private router: Router) { }

  canActivate(): Promise<boolean> {
    return this.auth.isLoggedInPromise()
      .then(isLoggedIn => {
        if (!isLoggedIn) {
          this.router.navigate(["/login"]);
        }
        return isLoggedIn;
      });
    }
  }

公共路由應該這樣配置:

{
  path: "login",
  component: LoginComponent,
  data: { isPublic: true }
}

這種實現的好處是默認情況下一切都受到保護,並且應該明確配置公共路由,這將減少使某些路由不受保護的可能性。 還將將此重構為某種服務,以便能夠在多個應用程序中使用它。

受到這個答案的啟發。

訂閱路由事件的問題是導航已經開始並且歷史已經更新,這使得很難像守衛那樣以可靠的方式阻止導航。

但是 Angular 已經學會了為你提供一種方法來配置守衛和解析器應該如何直接在你的routes.ts表現:

export const routes: Routes = [
  {
    path: '404',
    component: NotFoundComponent
  },
  {
    path: '',
    canActivate: [AuthGuard],
    runGuardsAndResolvers: 'always',
    children: [
       ....
    ]
  }
]

這是文檔: https : //angular.io/api/router/RunGuardsAndResolvers

有一篇很好的博文解釋了您的選擇: https ://juristr.com/blog/2019/01/Explore-Angular-Routers-runGuardsAndResolvers/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM