Maak gebruik van de gestructureerde architectuur van Nest om veilige en efficiënte REST API's te bouwen.
Express.js is een geweldige technologie voor het bouwen van veilige en robuuste REST API's, maar biedt geen vooraf gedefinieerde structuur. Dankzij het minimalistische karakter kunt u essentiële aspecten zoals routering, codeorganisatie en beveiligingsmaatregelen handmatig of door gebruik te maken van beschikbare middleware en bibliotheken afhandelen.
Nest.js daarentegen, gebouwd bovenop Express.js en Node.js, introduceert een abstractie op een hoger niveau die een duidelijke structuur, een robuuste benadering van de codeorganisatie en een vereenvoudigde implementatie biedt details. In wezen biedt Nest.js een meer gestructureerde architectuur voor het bouwen van efficiënte en veilige backend-API's en -services.
Een Nest.js-project opzetten
Om aan de slag te gaan, moet je eerst de opdrachtregel (CLI) van Nest.js wereldwijd installeren door de onderstaande opdracht uit te voeren:
npm i -g @nestjs/cli
Zodra de installatie is voltooid, ga je gang en maak je een nieuw project aan door het volgende uit te voeren:
nest nieuw nest-jwt-api
Vervolgens zal Nest.js CLI u vragen een pakketbeheerder te kiezen om de afhankelijkheden te installeren. Voor deze zelfstudie gebruiken we npm, de Node Package Manager. Selecteer npm en wacht terwijl de CLI een standaard Nest.js-project maakt en alle vereiste configuratiebestanden en initiële afhankelijkheden installeert die nodig zijn om de applicatie uit te voeren.
Nadat het project is ingesteld, navigeert u naar de projectdirectory en start u de ontwikkelserver.
cd nest-jwt-api
npm-run start
Voer ten slotte de onderstaande opdracht uit om de pakketten te installeren die we voor dit project zullen gebruiken.
npm install mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt
U kunt de code van dit project hierin vinden GitHub-opslagplaats.
MongoDB-databaseverbinding configureren
Zet lokaal een MongoDB-database op of configureer een MongoDB-cluster in de cloud. Kopieer na het instellen van de database de URI-tekenreeks voor de databaseverbinding, maak een .env bestand in de hoofdmap van onze projectmap en plak de verbindingsreeks in:
MONGO_URI="verbindingsreeks"
Werk vervolgens de app.module.ts in de src directory-bestand om Mongoose als volgt te configureren:
importeren { Module } van'@nestjs/common';
importeren { Configuratiemodule } van'@nestjs/config';
importeren { Mongoose-module } van'@nestjs/mangoest';
importeren { AppController } van'./app.controller';
importeren { AppService } van'./app.service';
importeren { UserAuth-module } van'./user-auth/user-auth.module';@module({
invoer: [
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: WAAR,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuth-module,
],
controllers: [AppController],
aanbieders: [AppService],
})
exporterenklas App-module {}
De verstrekte code configureert drie essentiële modules voor de Nest.js-toepassing: Configuratiemodule voor omgevingsconfiguratie, Mongoose-module voor het tot stand brengen van de MongoDB-verbinding, en UserAuth-module voor gebruikersauthenticatie. Houd er rekening mee dat er in dit stadium een fout kan optreden sinds de UserAuth-module is nog niet gedefinieerd, maar we zullen het in de volgende sectie maken.
De gebruikersauthenticatiemodule maken
Om schone en overzichtelijke code te behouden, maakt u een gebruikersauthenticatiemodule door de volgende opdracht uit te voeren.
nest g module gebruiker-auth
De Nest.js CLI-tool genereert automatisch de vereiste modulebestanden. Bovendien zal het de app.module.ts bestand, waarin de nodige wijzigingen met betrekking tot de gebruikersauthenticatiemodule zijn opgenomen.
U kunt ervoor kiezen om de configuratiebestanden van het hoofdproject handmatig te maken, maar de CLI-tool vereenvoudigt dit dit proces door automatisch de vereiste items te maken, naast het dienovereenkomstig bijwerken van de wijzigingen in de app.module.ts bestand.
Maak een gebruikersschema
Binnen de nieuw gecreëerde gebruiker-auth map in de src map, maak een nieuwe schema's/user-auth.schema.ts -bestand en voeg de volgende code toe om een Mongoose-schema te maken voor het Gebruiker model
importeren { Prop, Schema, SchemaFactory } van'@nestjs/mangoest';
importeren { Document } van'mangoest';@Schema({ tijdstempels: WAAR })
exporterenklas Gebruiker {
@Prop()
gebruikersnaam: snaar;
@Prop()
wachtwoord: snaar;
}
exporterentype UserDocument = Gebruiker & Document;
exporterenconst UserSchema = SchemaFactory.createForClass (Gebruiker);
De gebruikersverificatieservice maken
Laten we nu de gebruikersauthenticatieservice maken die de authenticatielogica voor de REST API zal beheren door de onderstaande opdracht uit te voeren:
nest g service gebruiker-auth
Deze opdracht maakt een gebruiker-auth.service.ts bestand in de gebruikersauthenticatiemap. Open dit bestand en werk het bij met de volgende code.
- Voer eerst de volgende invoer uit.
importeren { Injecteerbaar, NotFoundException, Logger, UnauthorizedException } van'@nestjs/common';
importeren { Injecteer Model } van'@nestjs/mangoest';
importeren { Model } van'mangoest';
importeren { Gebruiker } van'./schemas/user-auth.schema';
importeren * als bcrypt van'bcrypt';
importeren { JwtService } van'@nestjs/jwt'; - Maak dan een UserAuthService klasse die de functionaliteit omvat voor gebruikersregistratie, login en het ophalen van alle gebruikersgegevensroutes.
@Injecteerbaar()
exporterenklas UserAuthService {
privaat alleen-lezen logger = nieuw Logboek (UserAuthService.naam);
constructeur(@InjectModel(Gebruikersnaam) privaat userModel: model, privaat jwtService: JwtService ) {}
asynchroon registreerGebruiker (gebruikersnaam: snaar, wachtwoord: snaar): Beloftesnaar }> {
poging {
const hasj = wachten bcrypt.hash (wachtwoord, 10);
wachtendit.userModel.create({ gebruikersnaam, wachtwoord: hash });
opbrengst { bericht: 'Gebruiker succesvol geregistreerd' };
} vangst (fout) {
gooiennieuwFout('Er is een fout opgetreden bij het registreren van de gebruiker');
}
}asynchroon loginGebruiker (gebruikersnaam: snaar, wachtwoord: snaar): Belofte<snaar> {
poging {
const gebruiker = wachtendit.userModel.findOne({ gebruikersnaam });
als (!gebruiker) {
gooiennieuw NietgevondenUitzondering('Gebruiker niet gevonden');
}
const wachtwoordMatch = wachten bcrypt.compare (wachtwoord, gebruiker.wachtwoord);
als (!wachtwoordMatch) {
gooiennieuw Ongeautoriseerde uitzondering('Ongeldige inloggegevens');
}
const payload = { userId: gebruiker._id };
const teken = dit.jwtService.sign (payload);
opbrengst teken;
} vangst (fout) {
troosten.log (fout);
gooiennieuw Ongeautoriseerde uitzondering('Er is een fout opgetreden bij het inloggen');
}
}
asynchroon getGebruikers(): Belofte
{
poging {
const gebruikers = wachtendit.userModel.find({});
opbrengst gebruikers;
} vangst (fout) {
dit.logger.fout(`Er is een fout opgetreden bij het ophalen van gebruikers: ${error.bericht}`);
gooiennieuwFout('Er is een fout opgetreden bij het ophalen van gebruikers');
}
}
}
De UserAuthService class implementeert de logica van gebruikersregistratie, login en het ophalen van gebruikersgegevens. Het gebruikt de gebruikerModel om te communiceren met de database en de vereiste acties uit te voeren, inclusief het hashen van het wachtwoord tijdens registratie, het valideren van inloggegevens en ten slotte het genereren van JWT-tokens na succes authenticatie.
Implementatie van de Authentication Guard
Om de veiligheid van gevoelige bronnen te waarborgen, is het van cruciaal belang om de toegang tot uitsluitend geautoriseerde gebruikers te beperken. Dit wordt bereikt door een beveiligingsmaatregel af te dwingen die de aanwezigheid van een geldige JWT verplicht stelt in daaropvolgende API-verzoeken aan beschermde eindpunten, in dit geval de gebruikers route. In de gebruiker-auth map, maak een nieuwe auth.bewaker.ts bestand en voeg onderstaande code toe.
importeren { CanActivate, ExecutionContext, Injectable, UnauthorizedException } van'@nestjs/common';
importeren { JwtService } van'@nestjs/jwt';
importeren { Verzoek } van'nadrukkelijk';
importeren { geheime sleutel } van'./config';@Injecteerbaar()
exporterenklas AuthGuard implementeert KanActiveren {
constructeur(privaat jwtService: JwtService) {}
asynchroon canActivate (context: ExecutionContext): Belofte<booleaans> {
const verzoek = context.switchToHttp().getRequest();
const teken = dit.extractTokenFromHeader (verzoek);
als (!fiche) {
gooiennieuw Niet-geautoriseerde uitzondering();
}
poging {
const laadvermogen = wachtendit.jwtService.verifyAsync (token, {
geheim: secretKey.secret,
});
verzoek['gebruiker'] = lading;
} vangst {
gooiennieuw Niet-geautoriseerde uitzondering();
}
opbrengstWAAR;
}
privaat extractTokenFromHeader (verzoek: verzoek): snaar | ongedefinieerd {
const [type, token] = request.headers.authorization?.split(' ')?? [];
opbrengsttype'Toonder'? token: ongedefinieerd;
}
}
De code implementeert een bewaker, zoals gespecificeerd in de officiële documentatie, om routes te beschermen en ervoor te zorgen dat alleen geverifieerde gebruikers met een geldig JWT-token er toegang toe hebben.
Het haalt het JWT-token uit de verzoekheader en verifieert de authenticiteit ervan met behulp van de JwtService, en wijst de gedecodeerde payload toe aan de verzoek['gebruiker'] eigendom voor verdere verwerking. Als het token ontbreekt of ongeldig is, gooit het een Ongeautoriseerde uitzondering om toegang tot de beveiligde route te voorkomen.
Maak nu config.ts bestand in dezelfde map en voeg de onderstaande code toe.
exporterenconst geheime sleutel = {
geheim: 'GEHEIME WAARDE.',
};
Deze geheime sleutel wordt gebruikt om de authenticiteit van JWT's te ondertekenen en te verifiëren. Het is essentieel om de sleutelwaarde veilig op te slaan om ongeoorloofde toegang te voorkomen en de integriteit van de JWT's te beschermen.
Definieer de API-controller
Maak een controller die de API-eindpunten voor gebruikersauthenticatie afhandelt.
nest g-controller gebruikersauth
Kopieer vervolgens de hierin verstrekte code GitHub-opslagplaatsbestanden voeg deze toe aan de gebruiker-auth.controller.ts bestand - het definieert de eindpunten voor gebruikersregistratie, login en het ophalen van gebruikersgegevens. De Gebruik Guards (AuthGuard) decorateur is inbegrepen om authenticatie af te dwingen voor de gebruikers ophalen eindpunt, zodat alleen geverifieerde gebruikers toegang krijgen.
Werk het bestand user-auth.module.ts bij
Werk het bestand bij om de wijzigingen in het project weer te geven gebruiker-auth.module.ts bestand om de benodigde modules, services en controllers voor gebruikersauthenticatie te configureren.
importeren {Module, NestModule, MiddlewareConsumer} van'@nestjs/common';
importeren { JwtModule } van'@nestjs/jwt';
importeren { UserAuthController} van'./user-auth.controller';
importeren { UserAuthService } van'./user-auth.service';
importeren { Mongoose-module } van'@nestjs/mangoest';
importeren { Gebruikersschema } van'./schemas/user-auth.schema';
importeren { geheime sleutel } van'./config';@module({
invoer: [
MongooseModule.forFeature([{ naam: 'Gebruiker', schema: Gebruikersschema }]),
JwtModule.register({
geheim: secretKey.secret,
signOptions: { verlooptIn: '1u' },
}),
],
controllers: [UserAuthController],
aanbieders: [UserAuthService],
})
exporterenklas UserAuth-module implementeert NestModule {
configureren (consument: MiddlewareConsumer) {
}
}
Start ten slotte de ontwikkelingsserver en test de API-eindpunten met behulp van Postman.
npm-run start
Veilige Nest.js REST API's bouwen
Het bouwen van veilige Nest.js REST API's vereist een alomvattende aanpak die verder gaat dan alleen vertrouwen op JWT's voor authenticatie en autorisatie. Hoewel JWT's belangrijk zijn, is het even cruciaal om aanvullende beveiligingsmaatregelen te implementeren.
Bovendien kunt u, door prioriteit te geven aan beveiliging in elke fase van API-ontwikkeling, de veiligheid van uw backend-systemen waarborgen.