標準的な解決策が見つかりませんでした。インターネットで提供される解決策は1ページに制限されています。そのため、自分で書いたものを共有することにしました。
ケースの説明
アプリケーションページは3つのグループに分かれています。
- 許可されたユーザーのみ
- 許可されていないユーザーのみ
- すべてのユーザー向け
どのページからでもログインまたはログアウトできます。
アクセスが制限されているページに出入りする場合は、許可されているページに移動する必要があります。
ページに制限がない場合は、現在のページにとどまる必要があります。
理解を深めるために、次のことを知っておくことをお勧めします。
決定
ページへのアクセス権の区別は、ガード-CanActivateを介して実行されます。チェックはページに移動したときに実行されますが、移行が既に行われている場合は権限の変更には反応しません。アクセス権のロジックの重複を避けるため、ガードを強制的に再起動します。
現在のページのガードを再開するには、現在のURLをナビゲートします。そして、戦略Router.onSameUrlNavigationとRoute.runGuardsAndResolversへの変更。
これが既製のソリューションです。詳細については、次のセクションをご覧ください。
import { Injectable } from '@angular/core';
import { ActivatedRoute, PRIMARY_OUTLET, Router, RunGuardsAndResolvers } from '@angular/router';
@Injectable()
export class GuardControlService {
constructor(
private route: ActivatedRoute,
private router: Router,
) {}
/**
* guard- url
*/
forceRunCurrentGuards(): void {
// Router.onSameUrlNavigation url
const restoreSameUrl = this.changeSameUrlStrategy(this.router, 'reload');
// ActivatedRoute primary outlet
const primaryRoute: ActivatedRoute = this.getLastRouteForOutlet(this.route.root, PRIMARY_OUTLET);
// runGuardsAndResolvers ActivatedRoute url
const restoreRunGuards = this.changeRunGuardStrategies(primaryRoute, 'always');
//
this.router.navigateByUrl(
this.router.url
).then(() => {
// onSameUrlNavigation
restoreSameUrl();
// runGuardsAndResolvers
restoreRunGuards();
});
}
/**
* onSameUrlNavigation
* @param router - Router,
* @param strategy -
* @return callback
*/
private changeSameUrlStrategy(router: Router, strategy: 'reload' | 'ignore'): () => void {
const onSameUrlNavigation = router.onSameUrlNavigation;
router.onSameUrlNavigation = strategy;
return () => {
router.onSameUrlNavigation = onSameUrlNavigation;
}
}
/**
* route outlet-
* @param route - Route
* @param outlet - outlet-,
* @return ActivatedRoute outlet
*/
private getLastRouteForOutlet(route: ActivatedRoute, outlet: string): ActivatedRoute {
if (route.children?.length) {
return this.getLastRouteForOutlet(
route.children.find(item => item.outlet === outlet),
outlet
);
} else {
return route;
}
}
/**
* runGuardsAndResolvers ActivatedRoute ,
* @param route - ActivatedRoute
* @param strategy -
* @return callback
*/
private changeRunGuardStrategies(route: ActivatedRoute, strategy: RunGuardsAndResolvers): () => void {
const routeConfigs = route.pathFromRoot
.map(item => {
if (item.routeConfig) {
const runGuardsAndResolvers = item.routeConfig.runGuardsAndResolvers;
item.routeConfig.runGuardsAndResolvers = strategy;
return runGuardsAndResolvers;
} else {
return null;
}
});
return () => {
route.pathFromRoot
.forEach((item, index) => {
if (item.routeConfig) {
item.routeConfig.runGuardsAndResolvers = routeConfigs[index];
}
});
}
}
}
追加のソリューションの説明
ガードを再起動しようとする最初のことは、現在のURLへのナビゲーションを使用することです。
this.router.navigateByUrl(this.router.url);
ただし、デフォルトでは、現在のURL遷移イベントは無視され、何も起こりません。これを機能させるには、ルーティングを構成する必要があります。
ルーティングの設定
1.ルーター戦略を変更します。onSameUrlNavigation
onSameUrlNavigationは、次の値を取ることができます。
onSameUrlNavigation: 'reload' | 'ignore';
現在のURLへの遷移に対する感度を高めるには、「reload」を設定する必要があります。
ポリシーの変更は再読み込みされませんが、追加のナビゲーションイベントが生成されます。サブスクリプションを通じて取得できます。
this.router.events.subscribe();
2.ルート戦略を変更します。runGuardsAndResolvers
runGuardsAndResolversは、次の値を取ることができます。
type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
現在のURLへの移行に対する感度を高めるには、「常に」を設定する必要があります。
アプリケーション構成中のルーティングの構成
onSameUrlNavigation:
const routes: : Route[] = [];
@NgModule({
imports: [
RouterModule.forRoot(
routes,
{ onSameUrlNavigation: 'reload' }
)
]
})
runGuardsAndResolvers:
const routes: Route[] = [
{
path: '',
component: AppComponent,
runGuardsAndResolvers: 'always',
}
];
実行時のルーティングの構成
constructor(
private router: Router,
private route: ActivatedRoute
) {
this.router.onSameUrlNavigation = 'reload';
this.route.routeConfig.runGuardsAndResolvers = 'always';
}
ガードの再起動
ある特定のページのガードを再起動するには、構成中にルーティングを構成するだけで十分です。
ただし、任意のページのガードをリロードするには、各ルートでrunGuardsAndResolversを変更すると、不要なチェックが発生します。そして、このパラメータを常に覚えておく必要があります-エラーに対して。
このケースでは、アプリケーションの設定に制限がないページの再起動を想定しているため、次のものが必要です。
1. onSameUrlNavigationを置き換え、現在の値を維持します
// Router.onSameUrlNavigation url
const restoreSameUrl = this.changeSameUrlStrategy(this.router, 'reload');
...
/**
* onSameUrlNavigation
* @param router - Router,
* @param strategy -
* @return callback
*/
private changeSameUrlStrategy(router: Router, strategy: 'reload' | 'ignore'): () => void {
const onSameUrlNavigation = router.onSameUrlNavigation;
router.onSameUrlNavigation = strategy;
return () => {
router.onSameUrlNavigation = onSameUrlNavigation;
}
}
2.現在のURLのActivatedRouteを取得します
インジェクトActivatedRouteはサービスで実行されるため、結果のActivatedRouteは現在のURLに関連付けられません。
現在のURLのActivatedRouteは最後のプライマリアウトレットにあり、それを見つける必要があります。
// ActivatedRoute primary outlet
const primaryRoute: ActivatedRoute = this.getLastRouteForOutlet(this.route.root, PRIMARY_OUTLET);
...
/**
* route outlet-
* @param route - Route
* @param outlet - outlet-,
* @return ActivatedRoute outlet
*/
private getLastRouteForOutlet(route: ActivatedRoute, outlet: string): ActivatedRoute {
if (route.children?.length) {
return this.getLastRouteForOutlet(
route.children.find(item => item.outlet === outlet),
outlet
);
} else {
return route;
}
}
3.現在の値を維持したまま、すべてのActivatedRouteとその祖先のrunGuardsAndResolversを置き換えます
アクセスを制限するガードは、現在のActivatedRouteの任意の祖先に配置できます。すべての祖先はpathFromRootにあります。
// runGuardsAndResolvers ActivatedRoute url
const restoreRunGuards = this.changeRunGuardStrategies(primaryRoute, 'always');
...
/**
* runGuardsAndResolvers ActivatedRoute ,
* @param route - ActivatedRoute
* @param strategy -
* @return callback
*/
private changeRunGuardStrategies(route: ActivatedRoute, strategy: RunGuardsAndResolvers): () => void {
const routeConfigs = route.pathFromRoot
.map(item => {
if (item.routeConfig) {
const runGuardsAndResolvers = item.routeConfig.runGuardsAndResolvers;
item.routeConfig.runGuardsAndResolvers = strategy;
return runGuardsAndResolvers;
} else {
return null;
}
});
return () => {
route.pathFromRoot
.forEach((item, index) => {
if (item.routeConfig) {
item.routeConfig.runGuardsAndResolvers = routeConfigs[index];
}
});
}
}
4.現在のURLに移動します
this.router.navigateByUrl(this.router.url);
5.runGuardsAndResolversとonSameUrlNavigationを元の状態に戻します
restoreRunGuards();
restoreSameUrl();
6.1つの機能でステージを組み合わせる
constructor(
private route: ActivatedRoute,
private router: Router,
) {}
/**
* guard- url
*/
forceRunCurrentGuards(): void {
// Router.onSameUrlNavigation url
const restoreSameUrl = this.changeSameUrlStrategy(this.router, 'reload');
// ActivatedRoute primary outlet
const primaryRoute: ActivatedRoute = this.getLastRouteForOutlet(this.route.root, PRIMARY_OUTLET);
// runGuardsAndResolvers ActivatedRoute url
const restoreRunGuards = this.changeRunGuardStrategies(primaryRoute, 'always');
//
this.router.navigateByUrl(
this.router.url
).then(() => {
// onSameUrlNavigation
restoreSameUrl();
// runGuardsAndResolvers
restoreRunGuards();
});
}
この記事がお役に立てば幸いです。他に解決策があれば、コメントで見て喜んでいます。