Je travaille sur une application qui a beaucoup de rôles dont j'ai besoin pour utiliser des gardes pour bloquer la navigation vers des parties de l'application en fonction de ces rôles. Je me rends compte que je peux créer des classes de garde individuelles pour chaque rôle, mais que je préfère avoir une classe dans laquelle je pourrais d'une manière ou d'une autre passer un paramètre. En d'autres termes, j'aimerais pouvoir faire quelque chose de similaire à ceci:
{
path: 'super-user-stuff',
component: SuperUserStuffComponent,
canActivate: [RoleGuard.forRole('superUser')]
}
Mais comme tout ce que vous passez est le nom de type de votre garde, vous ne pouvez pas penser à un moyen de le faire. Dois-je simplement mordre la balle et écrire les classes de garde individuelles par rôle et briser mon illusion d'élégance en ayant un seul type paramétré à la place?
la source
roles
objet et le garde-route sont liés sans savoir comment le code fonctionne à l'avance. Il est nul qu'Angular ne prenne pas en charge un moyen de le faire de manière plus déclarative. (Pour être clair, c'est moi qui déplore Angular pas cette solution parfaitement raisonnable.)Voici mon avis à ce sujet et une solution possible au problème du fournisseur manquant.
Dans mon cas, nous avons un garde qui prend une permission ou une liste d'autorisations comme paramètre, mais c'est la même chose d'avoir un rôle.
Nous avons une classe pour traiter avec les gardes d'authentification avec ou sans permission:
Cela concerne la vérification de la session active de l'utilisateur, etc.
Il contient également une méthode utilisée pour obtenir un garde d'autorisation personnalisé, qui dépend en fait de
AuthGuardService
lui - mêmeCela nous permet d'utiliser la méthode pour enregistrer des gardes personnalisés en fonction du paramètre d'autorisations dans notre module de routage:
La partie intéressante de
forPermission
estAuthGuardService.guards.push
- cela garantit essentiellement qu'à tout momentforPermissions
est appelé pour obtenir une classe de garde personnalisée, il la stockera également dans ce tableau. Ceci est également statique sur la classe principale:Ensuite, nous pouvons utiliser ce tableau pour enregistrer tous les gardes - ce n'est pas grave tant que nous nous assurons qu'au moment où le module d'application enregistre ces fournisseurs, les routes ont été définies et toutes les classes de garde ont été créées (par exemple, vérifiez l'ordre d'importation et gardez ces fournisseurs aussi bas que possible dans la liste - avoir un module de routage aide):
J'espère que cela t'aides.
la source
ERROR in Error during template compile of 'RoutingModule' Function calls are not supported in decorators but 'PermGuardService' was called.
La solution de @ AluanHaddad donne l'erreur "pas de fournisseur". Voici un correctif pour cela (cela semble sale, mais je n'ai pas les compétences pour en faire un meilleur).
Conceptuellement, j'enregistre, en tant que fournisseur, chaque classe générée dynamiquement créée par
roleGuard
.Donc, pour chaque rôle vérifié:
tu aurais dû:
Cependant, la solution de @ AluanHaddad telle quelle générera une nouvelle classe pour chaque appel à
roleGuard
, même si leroles
paramètre est le même. Son utilisationlodash.memoize
ressemble à ceci:Notez que chaque combinaison de rôles génère une nouvelle classe, vous devez donc vous inscrire en tant que fournisseur pour chaque combinaison de rôles. Ie si vous avez:
canActivate: [roleGuard('foo')]
etcanActivate: [roleGuard('foo', 'bar')]
vous devrez vous inscrire à la fois:providers[roleGuard('foo'), roleGuard('foo', 'bar')]
Une meilleure solution serait d'enregistrer automatiquement les fournisseurs dans une collection de fournisseurs mondiaux à l'intérieur
roleGuard
, mais comme je l'ai dit, je n'ai pas les compétences pour mettre en œuvre cela.la source