0x0 EinführungUnter Systemautorisierung versteht man den Vorgang, bei dem angemeldete Benutzer Vorgänge ausführen. Beispielsweise können Administratoren Benutzervorgänge am System ausführen und Website-Beiträge verwalten, während Nicht-Administratoren Vorgänge wie das autorisierte Lesen von Beiträgen ausführen können. Daher ist zur Implementierung der Systemautorisierung ein Mechanismus zur Identitätsauthentifizierung erforderlich. Im Folgenden wird eine Implementierung des grundlegendsten rollenbasierten Zugriffskontrollsystems beschrieben. 0x1 RBAC-ImplementierungDie rollenbasierte Zugriffskontrolle (RBAC) ist ein Zugriffskontrollmechanismus, der unabhängig von Rollenberechtigungen und definierten Richtlinien ist. Erstellen Sie zunächst eine Datei role.enum.ts, die die Aufzählungsinformationen der Systemrolle enthält: export enum Rolle { Benutzer = "Benutzer", Admin = "Administrator" } Handelt es sich um ein komplexeres System, empfiehlt es sich, die Rolleninformationen zur besseren Verwaltung in einer Datenbank zu speichern. Erstellen Sie dann einen Dekorator und verwenden Sie @Roles(), um die angegebenen Ressourcenrollen auszuführen, die für den Zugriff erforderlich sind. Erstellen Sie roles.decorator.ts: importiere { SetMetadata } von '@nestjs/common' importiere { Rolle } aus './role.enum' export const ROLES_KEY = "Rollen" export const Roles = (...Rollen: Rolle[]) => SetMetadata(ROLES_KEY, Rollen) Das Obige erstellt einen Dekorator namens @Roles(), der zum Dekorieren jedes Routen-Controllers, wie etwa der Benutzererstellung, verwendet werden kann: @Post() @Rollen(Rolle.Admin) erstellen(@Body() createUserDto: CreateUserDto): Promise<UserEntity> { gib dies zurück.userService.create(createUserDto) } Erstellen Sie abschließend eine RolesGuard-Klasse, die die dem aktuellen Benutzer zugewiesene Rolle mit der vom aktuellen Routing-Controller benötigten Rolle vergleicht. Um auf die Routing-Rolle (benutzerdefinierte Metadaten) zuzugreifen, wird die Tool-Klasse Reflector verwendet. Erstellen Sie eine neue Datei „roles.guard.ts“: importiere { Injectable, CanActivate, ExecutionContext } von '@nestjs/common' importiere { Reflektor } von '@nestjs/core' importiere { Rolle } aus './role.enum' importiere { ROLES_KEY } aus './roles.decorator' @Injizierbar() Exportklasse RolesGuard implementiert CanActivate { Konstruktor (privater Reflektor: Reflektor) {} kannAktivieren(Kontext: Ausführungskontext): boolean { const requireRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [context.getHandler(), context.getClass()]) wenn (!erfordernRollen) { returniere wahr } const { Benutzer } = Kontext.switchToHttp().getRequest() returniere requireRoles.some(Rolle => Benutzer.Rollen?.includes(Rolle)) } } Angenommen, request.user enthält das Rollenattribut: Klasse Benutzer { // ...andere Eigenschaften Rollen: Rolle[] } Anschließend wird RolesGuard global im Controller registriert: Anbieter: { bieten: APP_GUARD, useClass: Rollenwächter } ] Wenn ein Benutzer auf eine Anforderung zugreift, die über den Umfang der Rolle hinausgeht: { "Statuscode": 403, "message": "Verbotene Ressource", "error": "Verboten" } 0x2 Anspruchsbasierte AutorisierungNach dem Erstellen einer Identität kann das System der Identität eine oder mehrere deklarative Berechtigungen zuweisen, was bedeutet, dass dem aktuellen Benutzer mitgeteilt wird, was er tun soll, anstatt wer der aktuelle Benutzer ist. Im Nest-System wird die deklarative Autorisierung ähnlich wie RBAC oben implementiert, es gibt jedoch einen Unterschied. Anstatt eine bestimmte Rolle zu beurteilen, müssen Berechtigungen verglichen werden. Jedem Benutzer wird ein Satz von Berechtigungen zugewiesen, z. B. durch Definieren eines @RequirePermissions()-Dekorators und anschließendem Zugriff auf die erforderlichen Berechtigungsattribute: @Post() @RequirePermissions(Berechtigung.CREATE_USER) erstellen(@Body() createUserDto: CreateUserDto): Promise<UserEntity> { gib dies zurück.userService.create(createUserDto) } Die Berechtigung ähnelt der Rollenaufzählung in PRAC, die die Berechtigungsgruppen enthält, auf die das System zugreifen kann: export enum Rolle { CREATE_USER = ['hinzufügen', 'lesen', 'aktualisieren', 'löschen'], READ_USER = ['lesen'] } 0x3 Integriertes CASLCASL ist eine homogene Autorisierungsbibliothek, die den Zugriff der Clients auf Routing-Controller-Ressourcen einschränken kann. Installationsabhängigkeiten: Garn hinzufügen @casl/ability Das Folgende ist das einfachste Beispiel zur Implementierung des CASL-Mechanismus und zum Erstellen von zwei Entitätsklassen: Benutzer und Artikel: Klasse Benutzer { ID: Nummer isAdmin: Boolescher Wert } Die Entitätsklasse „Benutzer“ verfügt über zwei Attribute, nämlich die Benutzer-ID und ob der Benutzer über Administratorrechte verfügt. Klasse Artikel { ID: Nummer isPublished: Boolescher Wert authorId: Zeichenfolge } Die Entitätsklasse „Artikel“ verfügt über drei Attribute, nämlich die Artikelnummer, den Artikelstatus (ob er veröffentlicht wurde) und die Nummer des Autors, der den Artikel geschrieben hat. Basierend auf den beiden einfachsten Beispielen oben können wir die einfachste Funktion erstellen:
Für die oben genannten Funktionen können Sie eine Aktionsaufzählung erstellen, um die Vorgänge des Benutzers für die Entität darzustellen: export enum Aktion { Verwalten = "verwalten", Erstellen = "erstellen", Lesen = 'lesen', Update = "Aktualisieren", Löschen = "löschen", } „Manage“ ist ein spezielles Schlüsselwort in CASL, das bedeutet, dass jede beliebige Operation ausgeführt werden kann. Um die Funktion zu implementieren, müssen Sie die CASL-Bibliothek zweimal kapseln. Führen Sie nest-cli aus, um das erforderliche Geschäft zu erstellen: Nest G-Modul casl nest g Klasse casl/casl-ability.factory Definieren Sie die Methode createForUser() von CaslAbilityFactory, um Objekte für Benutzer zu erstellen: Typ Themen = InferSubjects<Typ des Artikels | Typ des Benutzers> | „alle“ Exporttyp AppAbility = Fähigkeit<[Aktion, Themen]> @Injizierbar() Exportklasse CaslAbilityFactory { createForUser(Benutzer: Benutzer) { const { kann, kann nicht, bauen } = neuer AbilityBuilder< Fähigkeit<[Aktion, Subjekte]> >(Fähigkeit als Fähigkeitsklasse<Anwendungsfähigkeit>); if (Benutzer.istAdmin) { can(Action.Manage, 'all') // Alle Lese- und Schreibvorgänge zulassen } else { kann(Action.Read, 'all') // schreibgeschützter Vorgang} kann(Aktion.Update, Artikel, { authorId: user.id }) kann nicht(Aktion.Löschen, Artikel, { ist veröffentlicht: true }) Rückgabebuild({ // Details: https://casl.js.org/v5/en/guide/subject-type-detection#use-classes-as-subject-types detectSubjectType: item => item.constructor als ExtractSubjectType<Subjekte> }) } } Importieren Sie es dann in CaslModule: importiere { Modul } von '@nestjs/common' importiere { CaslAbilityFactory } aus './casl-ability.factory' @Modul({ Anbieter: [CaslAbilityFactory], Exporte: [CaslAbilityFactory] }) Exportklasse CaslModule {} Importieren Sie dann CaslModule in ein beliebiges Unternehmen und fügen Sie es in den Konstruktor ein, um es zu verwenden: Konstruktor (private caslAbilityFactory: CaslAbilityFactory) {} const Fähigkeit = this.caslAbilityFactory.createForUser(Benutzer) wenn (Fähigkeit.kann(Aktion.Lesen, 'alle')) { // "Benutzer" kann sämtliche Inhalte lesen und schreiben} Wenn der aktuelle Benutzer kein Administrator ist und über normale Berechtigungen verfügt, kann er Artikel lesen, aber keine neuen Artikel erstellen oder vorhandene Artikel löschen: const Benutzer = neuer Benutzer() Benutzer.isAdmin = false const Fähigkeit = this.caslAbilityFactory.createForUser(Benutzer) Fähigkeit.kann(Aktion.Lesen, Artikel) // wahr Fähigkeit.kann(Aktion.Löschen, Artikel) // false Fähigkeit.kann(Aktion.Erstellen, Artikel) // false Dies ist offensichtlich problematisch. Wenn der aktuelle Benutzer der Autor des Artikels ist, sollte er Folgendes tun können: const Benutzer = neuer Benutzer() Benutzer-ID = 1 const Artikel = neuer Artikel() Artikel.AutorID = Benutzer-ID const Fähigkeit = this.caslAbilityFactory.createForUser(Benutzer) Fähigkeit.kann(Aktion.Update, Artikel) // wahr Artikel.Autoren-ID = 2 Fähigkeit.kann(Aktion.Update, Artikel) // false 0x4 PolizeiwacheDie obige einfache Implementierung genügt nicht den komplexeren Anforderungen in komplexen Systemen. Daher verwenden wir den vorherigen Authentifizierungsartikel, um den Autorisierungsstrategiemodus auf Klassenebene zu erweitern und die ursprüngliche CaslAbilityFactory-Klasse zu erweitern: importiere { AppAbility } von '../casl/casl-ability.factory' Schnittstelle IPolicyHandler { handle(Fähigkeit: AppAbility): Boolesch } Typ PolicyHandlerCallback = (Fähigkeit: AppAbility) => Boolesch Exporttyp PolicyHandler = IPolicyHandler | PolicyHandlerCallback Bietet Unterstützungsobjekte und Funktionen zur Richtlinienprüfung auf jedem Routing-Controller: IPolicyHandler und PolicyHandlerCallback. Erstellen Sie dann einen @CheckPolicies()-Decorator, um die angegebene Zugriffsrichtlinie für eine bestimmte Ressource auszuführen: exportiere const CHECK_POLICIES_KEY = "check_policy" export const CheckPolicies = (...handlers: PolicyHandler[]) => SetMetadata(CHECK_POLICIES_KEY, handlers) Erstellen Sie eine PoliciesGuard-Klasse, um alle an den Routing-Controller gebundenen Richtlinien zu extrahieren und auszuführen: @Injizierbar() Exportklasse PoliciesGuard implementiert CanActivate { Konstruktor( privater Reflektor: Reflektor, private caslAbilityFactory: CaslAbilityFactory, ) {} async kann aktivieren(Kontext: Ausführungskontext): Promise<boolean> { const policyHandlers = dies.reflector.get<PolicyHandler[]>( CHECK_POLICIES_KEY, Kontext.getHandler() ) || [] const { Benutzer } = Kontext.switchToHttp().getRequest() const Fähigkeit = this.caslAbilityFactory.createForUser(Benutzer) RückgaberichtlinieHandlers.every((handler) => this.execPolicyHandler(Handler, Fähigkeit) ) } private execPolicyHandler(handler: PolicyHandler, Fähigkeit: AppAbility) { wenn (Typ des Handlers === 'Funktion') { Rückgabehandler (Fähigkeit) } returniere Handler.Handle(Fähigkeit) } } Vorausgesetzt, request.user enthält eine Benutzerinstanz, werden policyHandler über den Dekorator @CheckPolicies() zugewiesen. Dabei wird aslAbilityFactory#create verwendet, um eine Ability-Objektmethode zu konstruieren, die überprüft, ob der Benutzer über ausreichende Berechtigungen zum Ausführen einer bestimmten Aktion verfügt. Anschließend wird dieses Objekt an die Methode zur Richtlinienbehandlung übergeben, die eine Implementierungsfunktion oder eine Instanz der Klasse IPolicyHandler sein kann. Außerdem wird eine handle()-Methode bereitgestellt, die einen booleschen Wert zurückgibt. @Erhalten() @UseGuards(RichtlinienGuard) @CheckPolicies((Fähigkeit: AppAbility) => Fähigkeit.kann(Aktion.Lesen, Artikel)) findeAlle() { gib this.articlesService.findAll() zurück } Sie können auch die Schnittstellenklasse IPolicyHandler definieren: Exportklasse ReadArticlePolicyHandler implementiert IPolicyHandler { handle(Fähigkeit: AppAbility) { Rückgabefähigkeit.kann(Aktion.Lesen, Artikel) } } Verwenden Sie es wie folgt: @Erhalten() @UseGuards(RichtlinienGuard) @CheckPolicies(neuer ReadArticlePolicyHandler()) findeAlle() { gibt this.articlesService.findAll() zurück } Dies ist das Ende dieses Artikels über das Beispiel der Autorisierungsüberprüfungsmethode von Nest.js. Weitere verwandte Inhalte zur Autorisierungsüberprüfung von Nest.js finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Zusammenfassung der Installation der grünen Version von MySQL5 unter Windows (empfohlen)
1. Hintergrund Sysbench ist ein Stresstest-Tool, ...
Vorwort: Ich wollte schon immer wissen, wie eine ...
Vor Kurzem musste ich den Server erneut einem Str...
Die Speichergröße und der Bereich jedes Gleitkomm...
In diesem Artikelbeispiel wird der spezifische Ja...
Vorwort Normaler Geschäftsbedarf: Hochladen von B...
Drei nützliche Codes, die Besuchern dabei helfen,...
Vorwort Als wir das Pferd geschrieben haben, wuss...
netem und tc: netem ist ein Netzwerksimulationsmo...
Beim Erstellen einer Website scheint die HTML-Spra...
Dokumentumfang Dieser Artikel behandelt den Modus...
=================================================...
Vor kurzem musste ich aus geschäftlichen Gründen ...
Letztes Jahr war der offene Brief ein großer Erfo...
Inhaltsverzeichnis Vorwort Lösung Konkrete Umsetz...