Saya tidak menemukan solusi standar, dan yang ditawarkan di Internet terbatas pada satu halaman. Oleh karena itu, saya menulis sendiri dan memutuskan untuk membagikannya.
Deskripsi kasus
Halaman aplikasi dibagi menjadi 3 kelompok:
- Hanya untuk pengguna resmi
- Hanya untuk pengguna yang tidak sah
- Untuk semua pengguna
Anda dapat masuk atau keluar di halaman mana pun.
Jika Anda masuk / keluar pada halaman dengan akses terbatas, maka Anda harus pergi ke halaman yang diizinkan.
Jika halaman tersebut tidak memiliki batasan, Anda harus tetap berada di halaman saat ini.
Untuk pemahaman yang lebih baik, disarankan untuk mengetahui tentang:
Keputusan
Diferensiasi hak akses ke halaman dilakukan melalui penjaga - CanActivate. Pemeriksaan dilakukan saat Anda membuka halaman, tetapi tidak bereaksi terhadap perubahan hak saat transisi telah dilakukan. Untuk menghindari duplikasi logika untuk hak akses, kami secara paksa memulai ulang penjaga.
Restart penjaga untuk halaman saat ini dilakukan dengan menavigasi url saat ini. Dan perubahan pada strategi Router.onSameUrlNavigation dan Route.runGuardsAndResolvers.
Berikut solusi yang sudah jadi. Lebih detail di bagian selanjutnya.
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];
}
});
}
}
}
Deskripsi solusi tambahan
Hal pertama yang ingin Anda coba untuk memulai ulang penjaga adalah menggunakan navigasi ke url saat ini.
this.router.navigateByUrl(this.router.url);
Namun, secara default, peristiwa transisi url saat ini diabaikan dan tidak ada yang terjadi. Agar ini berfungsi, Anda perlu mengkonfigurasi perutean.
Menyiapkan perutean
1. Ubah strategi Router. onSameUrlNavigation
onSameUrlNavigation dapat mengambil nilai berikut:
onSameUrlNavigation: 'reload' | 'ignore';
Untuk kepekaan terhadap transisi ke url saat ini, Anda perlu menyetel 'muat ulang'.
Perubahan kebijakan tidak memuat ulang, tetapi menghasilkan peristiwa navigasi tambahan. Itu dapat diperoleh melalui langganan:
this.router.events.subscribe();
2. Ubah strategi Rute. runGuardsAndResolvers
runGuardsAndResolvers dapat mengambil nilai berikut:
type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
Untuk kepekaan terhadap transisi ke url saat ini, Anda perlu menyetel 'selalu'.
Mengonfigurasi Perutean Selama Konfigurasi Aplikasi
onSameUrlNavigation:
const routes: : Route[] = [];
@NgModule({
imports: [
RouterModule.forRoot(
routes,
{ onSameUrlNavigation: 'reload' }
)
]
})
runGuardsAndResolvers:
const routes: Route[] = [
{
path: '',
component: AppComponent,
runGuardsAndResolvers: 'always',
}
];
Mengonfigurasi Perutean saat Waktu Proses
constructor(
private router: Router,
private route: ActivatedRoute
) {
this.router.onSameUrlNavigation = 'reload';
this.route.routeConfig.runGuardsAndResolvers = 'always';
}
Memulai kembali penjaga
Untuk memulai ulang pelindung satu halaman tertentu, cukup dengan mengonfigurasi perutean selama konfigurasi.
Tetapi untuk memuat ulang penjaga halaman mana pun, mengubah runGuardsAndResolvers di setiap Rute akan menyebabkan pemeriksaan yang tidak perlu. Dan kebutuhan untuk selalu mengingat parameter ini - untuk kesalahan.
Karena kasus kami mengasumsikan restart untuk halaman apa pun tanpa batasan dalam menyiapkan aplikasi, Anda memerlukan:
1. Ganti onSameUrlNavigation dan pertahankan nilai saat ini
// 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. Dapatkan ActivatedRoute untuk url saat ini
Karena ActivatedRoute yang diinjeksi dijalankan dalam layanan, ActivatedRoute yang dihasilkan tidak terkait dengan url saat ini.
ActivatedRoute untuk url saat ini terletak di outlet utama terakhir dan Anda perlu menemukannya:
// 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. Ganti runGuardsAndResolvers untuk semua ActivatedRoute dan leluhurnya, pertahankan nilai saat ini
Penjaga yang membatasi akses dapat ditemukan di salah satu leluhur ActivatedRoute saat ini. Semua leluhur berada di 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. Buka url saat ini
this.router.navigateByUrl(this.router.url);
5. Kembalikan runGuardsAndResolvers dan onSameUrlNavigation ke keadaan semula
restoreRunGuards();
restoreSameUrl();
6. Gabungkan tahapan dalam satu fungsi
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();
});
}
Semoga artikel ini bermanfaat bagi Anda. Jika ada solusi lain, saya akan senang melihatnya di komentar.