Angular Guards Prioritätsfalle / Sudo Null IT News

Angular hat ein großartiges Tool, um die Navigation zwischen Seiten standardmäßig einzuschränken. Aber wie jedes große Projekt hat es seine Tücken. Heute erzähle ich euch von einem davon.

Frischen Sie Ihr Wissen auf, bevor Sie diesen Artikel lesen Eckige Wachen (im Folgenden Wachen). Der Artikel handelt von CanActivate, aber das gilt auch für den Rest der Wachen. Kommen wir nun zur Geschichte der Priority Discovery.

Erster Versuch

Ich habe kürzlich eine neue Funktion für Administratoren entwickelt. Es war notwendig, den Zugriff auf die Seite einzuschränken – lassen Sie den Benutzer herein, wenn er eine bestimmte hat Feature-Flag und er ist ein Administrator, andernfalls nach Hause umleiten.

Es scheint eine triviale Aufgabe zu sein. Die Lösung ist mir mit Hilfe des CanActivate-Wächters sofort in den Sinn gekommen. Angenommen, es gibt bereits zwei Dienste für diese beiden Bedingungen. Als nächstes rufen wir die erforderlichen Methoden auf, kombinieren sie zu einem Observable, und wenn mindestens eine falsch zurückgegeben hat, leiten wir zur Hauptmethode weiter, wenn beide wahr sind, lassen wir den Benutzer auf die Seite gehen.

@Injectable() Exportklasse AdminGuard implementiert CanActivate { constructor( private readonly featureToggleService: FeatureToggleService, private readonly userService: UserService, private readonly router: Router ) {} canActivate(): Observable { const isAdminPageEnabled$ = this.featureToggleService.isAdminPageEnabled$.pipe(startWith(null)); const isAdmin$ = this.userService.isAdmin$.pipe(startWith(null)); return CombineLatest([isAdminPageEnabled$, isAdmin$]).pipe( first( conditions => conditions.some(condition => condition === false) || conditions.every(Boolean) ), map( ([isAdminPageEnabled, isAdmin]) => (isAdminPageEnabled && isAdmin) || this.router.createUrlTree([‘/’]) ) ); } }

Der Code funktioniert, aber wenn Sie genau hinsehen, können Sie besser schreiben. Die Implementierung hat zu viel Verantwortung für einen kleinen Wächter, und der Code ist nicht lesbar. Lassen Sie uns das beheben.

Refactoring

Da die Verantwortung zu groß ist, können wir die Wachen in zwei Teile aufteilen, da die CanActivate-Eigenschaft der Route entspricht Reihe von Wachen.

// admin-page-feature.guard.ts @Injectable() export class AdminPageFeatureGuard implementiert CanActivate { constructor( private readonly featureToggleService: FeatureToggleService, private readonly router: Router ) {} canActivate(): Observable { return this.featureToggleService.isAdminPageEnabled$.pipe( map( isAdminPageEnabled => isAdminPageEnabled || this.router.createUrlTree([‘/’]) ) ); } } // admin.guard.ts @Injectable() Exportklasse AdminGuard implementiert CanActivate { constructor( private readonly userService: UserService, private readonly router: Router ) {} canActivate(): Observable { return this.userService.isAdmin$.pipe( map(isAdmin => isAdmin || this.router.createUrlTree([‘/’])) ); } }

Jetzt gibt es zwei Guards, die wiederverwendet werden können, und der Code ist lesbar geworden. Es scheint, dass alles in Ordnung ist, aber in diesem Moment war ich von einer Frage verwirrt. Werden die Guards im CanActivate-Array sequentiell oder parallel ausgeführt?

const-Routen: Routen = [
{
path: ‘admin’,
component: AdminPageComponent,
canActivate: [AdminGuard, AdminPageFeatureGuard]}, ];

Es ist schlecht für mich, wenn die Wachen nacheinander ausgeführt werden, da es keinen Sinn macht, den Benutzer zu zwingen, auf jede Wache einzeln zu warten.

Ich habe etwas recherchiert und herausgefunden, dass sie parallel laufen, aber mit einigen Nuancen.

Wachprioritäten

In der entfernten siebten Version von Angular wurde die Priorität für Wachen eingeführt. Die an das Array für CanActivate übergebenen Guards werden parallel ausgeführt, aber der Router wartet, bis die höhere Priorität abgeschlossen ist, bevor er fortfährt. Die Priorität wird durch die Reihenfolge im CanActivate-Array bestimmt.

Schauen wir uns ein Beispiel an. Es gibt zwei Wächter HighPriorityGuard und LowPriorityGuard. Beide kehren zurück Observable. Wir navigieren die Route, auf der diese Wachen eingesetzt werden.

canActivate: [HighPriorityGuard, LowPriorityGuard]

Fakten über die Durchführung von Wachen:

  • Parallel laufen.

  • Wenn LowPriorityGuard zuerst UrlTree|false zurückgibt, wartet der Router dennoch darauf, dass HighPriorityGuard abgeschlossen ist, bevor er mit der Navigation beginnt.

  • Wenn HighPriorityGuard zuerst den UrlTree zurückgibt, wird sofort von HighPriorityGuard zum UrlTree navigiert.

  • Wenn LowPriorityGuard zuerst den UrlTree und dann HighPriorityGuard den UrlTree zurückgibt, erfolgt die Navigation zum UrlTree von HighPriorityGuard, da die höhere Priorität gewinnt.

  • Wenn HighPriorityGuard zuerst „true“ zurückgibt, wartet der Router auf LowPriorityGuard, da er nicht navigieren kann, bis sicher ist, dass alle Guards „true“ zurückgeben.

Wenn Sie Fragen zu Wächterprioritäten haben, gehen Sie bitte zu dieser Linkich habe eine kleine Demo vorbereitet, es wird einfacher sein, es dort herauszufinden.

Warum Prioritäten benötigt werden

Das Angular-Team hat Wachen Priorität eingeräumt, um das Problem der mehrfachen Umleitungen zu lösen. Nehmen wir an, die Anwendung hat zwei Wächter – Authentifizierung und Admin. Der Authentifizierungswächter leitet Sie zur Anmeldeseite weiter, wenn der Benutzer nicht angemeldet ist. Und der Admin-Wächter sendet an die Seite „Sie sind kein Administrator“, wenn der Benutzer nicht die erforderliche Rolle hat. Vor Version 7 von Angular erfolgte die Navigation über den Wächter, der als erster umleitete. Und es stellte sich heraus, dass ein nicht angemeldeter Benutzer auf die Seite „Sie sind kein Admin“ gelangen kann, weil der Admin-Wächter schneller abgeschlossen war.

Aber jetzt haben wir UrlTree und Guard-Priorität. Wenn der Authentifizierungswächter wichtiger ist, dann setzen wir ihn zuerst in das Array und geben ihm dadurch eine höhere Priorität, dann wartet der Router auf seine Ausführung und leitet von dort auf den UrlTree um.

Kurze Zusammenfassung

Geben Sie Wachen nur eine Verantwortung, dann sind sie leichter zu lesen und wiederzuverwenden. Aber denken Sie an die Prioritätsfalle. Wenn Sie den ersten Wächter in einer Sekunde und den zweiten in einer Stunde ausführen lassen und es keinen Unterschied in der Umleitung gibt, sollten Sie über die Reihenfolge im CanActivate/CanActivateChild/CanLoad/CanDeactivate-Array nachdenken, damit der Benutzer dies manchmal tut keine Stunde warten.

Ich habe eine eigene Lösung geschrieben, um die Priorität von Wächtern zu umgehen, weil ich mich grundsätzlich nicht damit zufrieden gab, den Benutzer warten zu lassen, aber dazu mehr im nächsten Artikel.

Similar Posts

Leave a Reply

Your email address will not be published.