Ich habe keine Standardlösung gefunden, und die im Internet angebotenen sind auf eine Seite beschränkt. Deshalb habe ich mein eigenes geschrieben und beschlossen, es zu teilen.
Fallschilderung
Bewerbungsseiten sind in 3 Gruppen unterteilt:
- Nur für autorisierte Benutzer
- Nur für nicht autorisierte Benutzer
- Für alle Benutzer
Sie können sich auf jeder Seite an- oder abmelden.
Wenn Sie eine Seite mit eingeschränktem Zugriff betreten / verlassen, müssen Sie zur zulässigen Seite wechseln.
Wenn die Seite keine Einschränkungen aufweist, müssen Sie auf der aktuellen Seite bleiben.
Zum besseren Verständnis ist es ratsam zu wissen über:
Entscheidung
Die Differenzierung der Zugriffsrechte auf Seiten erfolgt durch guard - CanActivate. Die Überprüfung wird ausgeführt, wenn Sie zur Seite gehen, reagiert jedoch nicht auf Änderungen der Rechte, wenn der Übergang bereits erfolgt ist. Um Doppellogik für Zugriffsrechte zu vermeiden, starten wir die Wachen zwangsweise neu.
Das Neustarten der Schutzvorrichtungen für die aktuelle Seite erfolgt durch Navigieren in der aktuellen URL. Und Änderungen an den Strategien Router.onSameUrlNavigation und Route.runGuardsAndResolvers.
Hier ist eine fertige Lösung. Weitere Details im nächsten Abschnitt.
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];
}
});
}
}
}
Zusätzliche Lösungsbeschreibung
Das erste, was Sie versuchen möchten, um die Wachen neu zu starten, ist die Navigation zur aktuellen URL.
this.router.navigateByUrl(this.router.url);
Standardmäßig wird das aktuelle URL-Übergangsereignis jedoch ignoriert und es passiert nichts. Damit dies funktioniert, müssen Sie das Routing konfigurieren.
Routing einrichten
1. Ändern Sie die Router-Strategie. onSameUrlNavigation
onSameUrlNavigation kann die folgenden Werte annehmen:
onSameUrlNavigation: 'reload' | 'ignore';
Um die Empfindlichkeit für den Übergang zur aktuellen URL zu gewährleisten, müssen Sie "Neu laden" festlegen.
Die Richtlinienänderung wird nicht neu geladen, sondern generiert ein zusätzliches Navigationsereignis. Es kann über ein Abonnement erhalten werden:
this.router.events.subscribe();
2. Ändern Sie die Routenstrategie. runGuardsAndResolvers
runGuardsAndResolvers kann die folgenden Werte annehmen:
type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean);
Um die Empfindlichkeit für den Übergang zur aktuellen URL zu gewährleisten, müssen Sie "immer" festlegen.
Konfigurieren des Routings während der Anwendungskonfiguration
onSameUrlNavigation:
const routes: : Route[] = [];
@NgModule({
imports: [
RouterModule.forRoot(
routes,
{ onSameUrlNavigation: 'reload' }
)
]
})
runGuardsAndResolvers:
const routes: Route[] = [
{
path: '',
component: AppComponent,
runGuardsAndResolvers: 'always',
}
];
Routing zur Laufzeit konfigurieren
constructor(
private router: Router,
private route: ActivatedRoute
) {
this.router.onSameUrlNavigation = 'reload';
this.route.routeConfig.runGuardsAndResolvers = 'always';
}
Wachen neu starten
Um die Schutzvorrichtungen einer bestimmten Seite neu zu starten, reicht es aus, das Routing während der Konfiguration zu konfigurieren.
Wenn Sie jedoch die Wachen einer Seite neu laden, führt das Ändern von runGuardsAndResolvers in jeder Route zu unnötigen Überprüfungen. Und die Notwendigkeit, sich immer an diesen Parameter zu erinnern - an Fehler.
Da in unserem Fall ein Neustart für jede Seite ohne Einschränkungen beim Einrichten der Anwendung vorausgesetzt wird, benötigen Sie:
1. Ersetzen Sie onSameUrlNavigation und behalten Sie den aktuellen Wert bei
// 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. Holen Sie sich ActivatedRoute für die aktuelle URL
Da die Injektion ActivatedRoute im Dienst ausgeführt wird, ist die resultierende ActivatedRoute nicht mit der aktuellen URL verknüpft.
ActivatedRoute für die aktuelle URL befindet sich in der letzten primären Steckdose und muss gefunden werden:
// 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. Ersetzen Sie runGuardsAndResolvers für alle ActivatedRoute und ihre Vorfahren, wobei Sie die aktuellen Werte beibehalten
Eine Wache, die den Zugriff einschränkt, kann sich in einem der Vorfahren der aktuellen ActivatedRoute befinden. Alle Vorfahren befinden sich in 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. Gehen Sie zur aktuellen URL
this.router.navigateByUrl(this.router.url);
5. Setzen Sie runGuardsAndResolvers und onSameUrlNavigation auf ihren ursprünglichen Zustand zurück
restoreRunGuards();
restoreSameUrl();
6. Kombinieren Sie Stufen in einer Funktion
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();
});
}
Ich hoffe, dieser Artikel hat Ihnen geholfen. Wenn es andere Lösungen gibt, würde ich mich freuen, sie in den Kommentaren zu sehen.