Nutzen Sie die strukturierte Architektur von Nest, um sichere und effiziente REST-APIs zu erstellen.
Express.js ist eine großartige Technologie zum Erstellen sicherer und robuster REST-APIs, bietet jedoch keine vordefinierte Struktur. Aufgrund seines minimalistischen Charakters können Sie wesentliche Aspekte wie Routing, Code-Organisation und Sicherheitsmaßnahmen entweder manuell oder durch Nutzung verfügbarer Middleware und Bibliotheken verwalten.
Im Gegensatz dazu führt Nest.js, das auf Express.js und Node.js aufbaut, eine Abstraktion auf höherer Ebene ein Das bietet eine klare Struktur, einen robusten Code-Organisationsansatz und eine vereinfachte Implementierung Einzelheiten. Im Wesentlichen bietet Nest.js eine strukturiertere Architektur zum Aufbau effizienter und sicherer Backend-APIs und -Dienste.
Einrichten eines Nest.js-Projekts
Um zu beginnen, müssen Sie zunächst die Befehlszeile (CLI) von Nest.js global installieren, indem Sie den folgenden Befehl ausführen:
npm i -g @nestjs/cli
Sobald die Installation abgeschlossen ist, erstellen Sie ein neues Projekt, indem Sie Folgendes ausführen:
Nest neue Nest-JWT-API
Als Nächstes werden Sie von der Nest.js-CLI aufgefordert, einen Paketmanager zum Installieren der Abhängigkeiten auszuwählen. Für dieses Tutorial verwenden wir npm, der Node Package Manager. Wählen npm und warten Sie, während die CLI ein grundlegendes Nest.js-Projekt erstellt und alle erforderlichen Konfigurationsdateien und anfänglichen Abhängigkeiten installiert, die zum Ausführen der Anwendung erforderlich sind.
Navigieren Sie nach der Einrichtung des Projekts zum Projektverzeichnis und starten Sie den Entwicklungsserver.
cd nest-jwt-api
NPM-Laufstart
Führen Sie abschließend den folgenden Befehl aus, um die Pakete zu installieren, die wir für dieses Projekt verwenden werden.
npm install mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt
Den Code dieses Projekts finden Sie hier GitHub-Repository.
Konfigurieren Sie die MongoDB-Datenbankverbindung
Richten Sie lokal eine MongoDB-Datenbank ein oder Konfigurieren Sie einen MongoDB-Cluster in der Cloud. Kopieren Sie nach dem Einrichten der Datenbank die URI-Zeichenfolge der Datenbankverbindung und erstellen Sie eine .env Datei im Stammverzeichnis unseres Projektordners und fügen Sie die Verbindungszeichenfolge ein:
MONGO_URI="Verbindungszeichenfolge"
Als nächstes aktualisieren Sie die app.module.ts im src Verzeichnisdatei, um Mongoose wie folgt zu konfigurieren:
importieren { Modul } aus'@nestjs/common';
importieren { ConfigModule } aus'@nestjs/config';
importieren { MongooseModule } aus'@nestjs/mongoose';
importieren {AppController} aus'./app.controller';
importieren { AppService } aus'./app.service';
importieren { UserAuthModule } aus'./user-auth/user-auth.module';@Modul({
Importe: [
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: WAHR,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModule,
],
Controller: [AppController],
Anbieter: [AppService],
})
ExportKlasse AppModule {}
Der bereitgestellte Code konfiguriert drei wesentliche Module für die Nest.js-Anwendung: ConfigModule zur Umgebungskonfiguration, MongooseModule zum Aufbau der MongoDB-Verbindung und UserAuthModule zur Benutzerauthentifizierung. Bitte beachten Sie, dass zu diesem Zeitpunkt möglicherweise ein Fehler auftritt UserAuthModule ist noch nicht definiert, aber wir werden es im nächsten Abschnitt erstellen.
Erstellen des Benutzerauthentifizierungsmoduls
Um einen sauberen und gut organisierten Code zu gewährleisten, erstellen Sie ein Benutzerauthentifizierungsmodul, indem Sie den folgenden Befehl ausführen.
Nest-G-Modul-Benutzerauthentifizierung
Das Nest.js-CLI-Tool generiert automatisch die erforderlichen Moduldateien. Darüber hinaus wird die aktualisiert app.module.ts Datei, die die notwendigen Änderungen im Zusammenhang mit dem Benutzerauthentifizierungsmodul enthält.
Sie können die wichtigsten Projektkonfigurationsdateien auch manuell erstellen, das CLI-Tool vereinfacht dies jedoch Dieser Prozess wird automatisch durchgeführt, indem die erforderlichen Elemente automatisch erstellt und die Änderungen entsprechend aktualisiert werden Die app.module.ts Datei.
Erstellen Sie ein Benutzerschema
Im Inneren des neu geschaffenen Benutzerauth Ordner im src Verzeichnis, erstellen Sie ein neues schemas/user-auth.schema.ts Datei und fügen Sie den folgenden Code hinzu, um ein Mongoose-Schema für zu erstellen Benutzer Modell
importieren { Prop, Schema, SchemaFactory } aus'@nestjs/mongoose';
importieren { Dokumentieren } aus'Mungo';@Schema({ Zeitstempel: WAHR })
ExportKlasse Benutzer {
@Stütze()
Nutzername: Zeichenfolge;
@Stütze()
Passwort: Zeichenfolge;
}
ExportTyp UserDocument = Benutzer & Dokument;
Exportconst UserSchema = SchemaFactory.createForClass (Benutzer);
Erstellen des Benutzerauthentifizierungsdienstes
Erstellen wir nun den Benutzerauthentifizierungsdienst, der die Authentifizierungslogik für die REST-API verwaltet, indem wir den folgenden Befehl ausführen:
Nest G-Dienst-Benutzerauthentifizierung
Dieser Befehl erstellt eine user-auth.service.ts Datei im Benutzerauth-Verzeichnis. Öffnen Sie diese Datei und aktualisieren Sie sie mit dem folgenden Code.
- Führen Sie zunächst die folgenden Importe durch.
importieren { Injectable, NotFoundException, Logger, UnauthorizedException } aus'@nestjs/common';
importieren {InjectModel} aus'@nestjs/mongoose';
importieren { Modell } aus'Mungo';
importieren { Benutzer } aus'./schemas/user-auth.schema';
importieren * als bcrypt aus'bcrypt';
importieren { JwtService } aus'@nestjs/jwt'; - Erstellen Sie dann eine UserAuthService Klasse, die die Funktionalität zur Benutzerregistrierung, Anmeldung und zum Abrufen aller Benutzerdatenrouten kapselt.
@Injectable()
ExportKlasse UserAuthService {
Privatgelände schreibgeschützter Logger = neu Logger (UserAuthService.name);
Konstrukteur(@InjectModel(Nutzername) Privatgelände userModel: Modell, Privatgelände jwtService: JwtService ) {}
asynchron registerUser (Benutzername: Zeichenfolge, Passwort: Zeichenfolge): VersprechenZeichenfolge }> {
versuchen {
const Hash = erwarten bcrypt.hash (Passwort, 10);
erwartenDas.userModel.create({ Benutzername, Passwort: Hash });
zurückkehren { Nachricht: „Benutzer erfolgreich registriert“ };
} fangen (Fehler) {
WurfneuFehler(„Beim Registrieren des Benutzers ist ein Fehler aufgetreten“);
}
}asynchron loginUser (Benutzername: Zeichenfolge, Passwort: Zeichenfolge): Versprechen<Zeichenfolge> {
versuchen {
const Benutzer = erwartenDas.userModel.findOne({ Benutzername });
Wenn (!Benutzer) {
Wurfneu NotFoundException('Benutzer nicht gefunden');
}
const passwortMatch = erwarten bcrypt.compare (Passwort, user.password);
Wenn (!passwordMatch) {
Wurfneu UnauthorizedException('Ungültige Login-Details');
}
const payload = { userId: user._id };
const Token = Das.jwtService.sign (Nutzlast);
zurückkehren Zeichen;
} fangen (Fehler) {
Konsole.log (Fehler);
Wurfneu UnauthorizedException(„Beim Anmelden ist ein Fehler aufgetreten“);
}
}
asynchron getUsers(): Versprechen
{
versuchen {
const Benutzer = erwartenDas.userModel.find({});
zurückkehren Benutzer;
} fangen (Fehler) {
Das.logger.error(„Beim Abrufen der Benutzer ist ein Fehler aufgetreten: ${error.message}`);
WurfneuFehler(„Beim Abrufen der Benutzer ist ein Fehler aufgetreten“);
}
}
}
Der UserAuthService Die Klasse implementiert die Logik der Benutzerregistrierung, Anmeldung und des Abrufens von Benutzerdaten. Es nutzt die userModel um mit der Datenbank zu interagieren und die erforderlichen Aktionen auszuführen, einschließlich des Hashings des Passworts Registrierung, Validierung der Anmeldeinformationen und schließlich Generierung von JWT-Tokens nach Erfolg Authentifizierung.
Implementierung des Authentication Guard
Um die Sicherheit sensibler Ressourcen zu gewährleisten, ist es wichtig, den Zugriff ausschließlich auf autorisierte Benutzer zu beschränken. Dies wird durch die Durchsetzung einer Sicherheitsmaßnahme erreicht, die das Vorhandensein eines gültigen JWT in nachfolgenden API-Anfragen an geschützte Endpunkte vorschreibt, in diesem Fall das Benutzer Route. Im Benutzerauth Verzeichnis, erstellen Sie ein neues auth.guard.ts Datei und fügen Sie den folgenden Code hinzu.
importieren { CanActivate, ExecutionContext, Injectable, UnauthorizedException } aus'@nestjs/common';
importieren { JwtService } aus'@nestjs/jwt';
importieren { Anfrage } aus'äußern';
importieren { geheimer Schlüssel } aus'./config';@Injectable()
ExportKlasse AuthGuard implementiert CanActivate {
Konstrukteur(Privatgelände jwtService: JwtService) {}
asynchron canActivate (Kontext: ExecutionContext): Versprechen<Boolescher Wert> {
const request = context.switchToHttp().getRequest();
const Token = Das.extractTokenFromHeader (Anfrage);
Wenn (!Zeichen) {
Wurfneu UnauthorizedException();
}
versuchen {
const Nutzlast = erwartenDas.jwtService.verifyAsync (Token, {
Geheimnis: SecretKey.secret,
});
Anfrage['Benutzer'] = Nutzlast;
} fangen {
Wurfneu UnauthorizedException();
}
zurückkehrenWAHR;
}
Privatgelände extractTokenFromHeader (Anfrage: Anfrage): Zeichenfolge | nicht definiert {
const [Typ, token] = request.headers.authorization?.split(' ')?? [];
zurückkehrenTyp'Träger'? Zeichen: nicht definiert;
}
}
Der Code implementiert a bewachen, wie in der offiziellen Dokumentation angegeben, um Routen zu schützen und sicherzustellen, dass nur authentifizierte Benutzer mit einem gültigen JWT-Token darauf zugreifen können.
Es extrahiert das JWT-Token aus dem Anforderungsheader und überprüft seine Authentizität mithilfe des JwtService, und weist die dekodierte Nutzlast dem zu Anfrage['Benutzer'] Eigentum zur Weiterverarbeitung. Wenn das Token fehlt oder ungültig ist, wird eine Fehlermeldung ausgegeben UnauthorizedException um den Zugriff auf die geschützte Route zu verhindern.
Jetzt erstellen config.ts Datei im selben Verzeichnis und fügen Sie den folgenden Code hinzu.
Exportconst SecretKey = {
Geheimnis: „Geheimer Wert.“,
};
Dieser geheime Schlüssel wird zum Signieren und Überprüfen der Authentizität von JWTs verwendet. Es ist wichtig, den Schlüsselwert sicher zu speichern, um unbefugten Zugriff zu verhindern und die Integrität der JWTs zu schützen.
Definieren Sie den API-Controller
Erstellen Sie einen Controller, der die API-Endpunkte für die Benutzerauthentifizierung verarbeitet.
Nest-G-Controller-Benutzerauthentifizierung
Kopieren Sie als Nächstes den darin bereitgestellten Code GitHub-Repository-Datei, und fügen Sie es hinzu user-auth.controller.ts Datei – sie definiert die Endpunkte für die Benutzerregistrierung, Anmeldung und den Abruf von Benutzerdaten. Der UseGuards (AuthGuard) Decorator ist enthalten, um die Authentifizierung für zu erzwingen getUsers Endpunkt, um sicherzustellen, dass nur authentifizierten Benutzern Zugriff gewährt wird.
Aktualisieren Sie die Datei user-auth.module.ts
Um die am Projekt vorgenommenen Änderungen widerzuspiegeln, aktualisieren Sie die user-auth.module.ts Datei zum Konfigurieren der erforderlichen Module, Dienste und Controller für die Benutzerauthentifizierung.
importieren { Modul, NestModule, MiddlewareConsumer } aus'@nestjs/common';
importieren { JwtModule } aus'@nestjs/jwt';
importieren { UserAuthController } aus'./user-auth.controller';
importieren { UserAuthService } aus'./user-auth.service';
importieren { MongooseModule } aus'@nestjs/mongoose';
importieren {Benutzerschema} aus'./schemas/user-auth.schema';
importieren { geheimer Schlüssel } aus'./config';@Modul({
Importe: [
MongooseModule.forFeature([{ name: 'Benutzer', Schema: UserSchema }]),
JwtModule.register({
Geheimnis: SecretKey.secret,
signOptions: { ExpiresIn: '1h' },
}),
],
Controller: [UserAuthController],
Anbieter: [UserAuthService],
})
ExportKlasse UserAuthModule implementiert NestModule {
configure (Verbraucher: MiddlewareConsumer) {
}
}
Zum Schluss starten Sie den Entwicklungsserver und testen die API-Endpunkte mit Postman.
NPM-Laufstart
Erstellen sicherer Nest.js-REST-APIs
Der Aufbau sicherer Nest.js-REST-APIs erfordert einen umfassenden Ansatz, der über die bloße Verwendung von JWTs zur Authentifizierung und Autorisierung hinausgeht. Während JWTs wichtig sind, ist es ebenso wichtig, zusätzliche Sicherheitsmaßnahmen zu implementieren.
Darüber hinaus können Sie die Sicherheit Ihrer Backend-Systeme gewährleisten, indem Sie der Sicherheit in jeder Phase der API-Entwicklung Priorität einräumen.