Använd Nests strukturerade arkitektur för att bygga säkra och effektiva REST API: er.
Express.js är en fantastisk teknik för att bygga säkra och robusta REST-API: er, men den ger ingen fördefinierad struktur. Dess minimalistiska karaktär gör att du kan hantera viktiga aspekter som routing, kodorganisation och säkerhetsåtgärder antingen manuellt eller genom att utnyttja tillgänglig mellanprogram och bibliotek.
Däremot introducerar Nest.js, byggt ovanpå Express.js och Node.js, en abstraktion på högre nivå som erbjuder en tydlig struktur, en robust kodorganisationsmetod och förenklad implementering detaljer. Nest.js tillhandahåller i huvudsak en mer strukturerad arkitektur för att bygga effektiva och säkra backend-API: er och tjänster.
Konfigurera ett Nest.js-projekt
För att komma igång måste du först installera Nest.js kommandorad (CLI) globalt genom att köra kommandot nedan:
npm i -g @nestjs/cli
När installationen är klar, fortsätt och skapa ett nytt projekt genom att köra:
häcka nytt nest-jwt-api
Nästa kommer Nest.js CLI att uppmana dig att välja en pakethanterare för att installera beroenden. För den här handledningen kommer vi att använda npm, Node Package Manager. Välj npm och vänta medan CLI skapar ett grundläggande Nest.js-projekt och installerar alla nödvändiga konfigurationsfiler och initiala beroenden som krävs för att köra programmet.
När projektet har ställts in, navigera till projektkatalogen och starta utvecklingsservern.
cd nest-jwt-api
npm körstart
Slutligen, kör kommandot nedan för att installera paketen vi kommer att använda för det här projektet.
npm installera mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt
Du kan hitta detta projekts kod i denna GitHub-förråd.
Konfigurera MongoDB Databas Connection
Ställ in en MongoDB-databas lokalt eller konfigurera ett MongoDB-kluster i molnet. Efter att ha ställt in databasen, kopiera databasanslutningens URI-sträng, skapa en .env fil i rotkatalogen i vår projektmapp och klistra in anslutningssträngen:
MONGO_URI="anslutningssträng"
Uppdatera sedan app.modul.ts i src katalogfil för att konfigurera Mongoose enligt följande:
importera { Modul } från'@nestjs/common';
importera { ConfigModule } från'@nestjs/config';
importera { MongooseModule } från'@nestjs/mongoose';
importera { AppController } från'./app.controller';
importera { AppService } från'./app.service';
importera { UserAuthModule } från'./user-auth/user-auth.module';@Modul({
importer: [
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: Sann,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModule,
],
kontroller: [AppController],
leverantörer: [AppService],
})
exporteraklass AppModule {}
Den medföljande koden konfigurerar tre viktiga moduler för Nest.js-appen: ConfigModule för miljökonfiguration, MongooseModule för att upprätta MongoDB-anslutningen, och UserAuthModule för användarautentisering. Observera att i det här skedet kan ett fel inträffa sedan UserAuthModule är inte definierat ännu, men vi skapar det i nästa avsnitt.
Skapar användarverifieringsmodulen
För att upprätthålla ren och välorganiserad kod, skapa en användarautentiseringsmodul genom att köra följande kommando.
nest g-modul användarauth
Nest.js CLI-verktyget genererar automatiskt de nödvändiga modulfilerna. Dessutom kommer den att uppdatera app.modul.ts fil, som innehåller nödvändiga ändringar relaterade till användarautentiseringsmodulen.
Du kan välja att skapa huvudprojektets konfigurationsfiler manuellt, men CLI-verktyget förenklar denna process genom att automatiskt skapa de nödvändiga objekten, förutom att uppdatera ändringarna därefter i de app.modul.ts fil.
Skapa ett användarschema
Inuti det nyskapade användarauth mapp i src katalog, skapa en ny schemas/user-auth.schema.ts fil och lägg till följande kod för att skapa ett Mongoose-schema för Användare modell
importera { Prop, Schema, SchemaFactory } från'@nestjs/mongoose';
importera { Dokument } från'mungo';@Schema({ tidsstämplar: Sann })
exporteraklass Användare {
@Stötta()
Användarnamn: sträng;
@Stötta()
Lösenord: sträng;
}
exporteratyp UserDocument = Användare & Dokument;
exporterakonst UserSchema = SchemaFactory.createForClass (Användare);
Skapar användarautentiseringstjänsten
Låt oss nu skapa användarautentiseringstjänsten som kommer att hantera autentiseringslogiken för REST API genom att köra kommandot nedan:
nest g-tjänst användarauth
Detta kommando kommer att skapa en user-auth.service.ts filen inuti user-auth-katalogen. Öppna den här filen och uppdatera den med följande kod.
- Gör först följande importer.
importera { Injectable, NotFoundException, Logger, UnauthorizedException } från'@nestjs/common';
importera { InjectModel } från'@nestjs/mongoose';
importera { Modell } från'mungo';
importera { Användare } från'./schemas/user-auth.schema';
importera * som bcrypt från'bcrypt';
importera { JwtService } från'@nestjs/jwt'; - Skapa sedan en UserAuthService klass som kapslar in funktionaliteten för användarregistrering, inloggning och hämtning av alla användardatarutter.
@Injicerbar()
exporteraklass UserAuthService {
privat skrivskyddad logger = ny Logger (UserAuthService.name);
konstruktör(@InjectModel(Användarnamn) privat användarmodell: Modell, privat jwtService: JwtService ) {}
asynkron registerUser (användarnamn: sträng, Lösenord: sträng): Löftesträng }> {
Prova {
konst hash = vänta bcrypt.hash (lösenord, 10);
väntadetta.userModel.create({ användarnamn, lösenord: hash });
lämna tillbaka { meddelande: "Användaren har registrerats framgångsrikt" };
} fånga (fel) {
kastanyFel("Ett fel uppstod när användaren registrerades");
}
}asynkron loginUser (användarnamn: sträng, Lösenord: sträng): Löfte<sträng> {
Prova {
konst användare = väntadetta.userModel.findOne({ användarnamn });
om (!användare) {
kastany NotFoundException('Användaren hittades inte');
}
konst passwordMatch = vänta bcrypt.compare (lösenord, användare.lösenord);
om (!passwordMatch) {
kastany UnauthorizedException("Ogiltiga inloggningsuppgifter");
}
konst nyttolast = { userId: user._id };
konst token = detta.jwtService.sign (nyttolast);
lämna tillbaka tecken;
} fånga (fel) {
trösta.log (fel);
kastany UnauthorizedException("Ett fel uppstod vid inloggning");
}
}
asynkron getUsers(): Löfte
{
Prova {
konst användare = väntadetta.userModel.find({});
lämna tillbaka användare;
} fånga (fel) {
detta.logger.error(`Ett fel uppstod när användare hämtades: ${error.message}`);
kastanyFel("Ett fel uppstod vid hämtning av användare");
}
}
}
De UserAuthService klass implementerar logiken för användarregistrering, inloggning och hämtning av användardata. Den använder användarmodell att interagera med databasen och utföra de nödvändiga åtgärderna inklusive hashning av lösenordet under registrering, validering av inloggningsuppgifter och slutligen generering av JWT-tokens efter framgångsrikt resultat autentisering.
Implementering av Authentication Guard
För att säkerställa säkerheten för känsliga resurser är det avgörande att begränsa åtkomsten uteslutande till behöriga användare. Detta uppnås genom att upprätthålla en säkerhetsåtgärd som kräver närvaron av en giltig JWT i efterföljande API-förfrågningar som görs till skyddade slutpunkter, i detta fall, användare rutt. I den användarauth katalog, skapa en ny auth.guard.ts fil och lägg till koden nedan.
importera { CanActivate, ExecutionContext, Injectable, UnauthorizedException } från'@nestjs/common';
importera { JwtService } från'@nestjs/jwt';
importera { Begäran } från'uttrycka';
importera { hemlig nyckel } från'./config';@Injicerbar()
exporteraklass AuthGuard redskap CanActivate {
konstruktör(privat jwtService: JwtService) {}
asynkron canActivate (sammanhang: ExecutionContext): Löfte<booleskt> {
konst request = context.switchToHttp().getRequest();
konst token = detta.extractTokenFromHeader (begäran);
om (!token) {
kastany UnauthorizedException();
}
Prova {
konst nyttolast = väntadetta.jwtService.verifyAsync (token, {
hemlighet: secretKey.secret,
});
begäran['användare'] = nyttolast;
} fånga {
kastany UnauthorizedException();
}
lämna tillbakaSann;
}
privat extractTokenFromHeader (begäran: Begäran): sträng | odefinierad {
konst [typ, token] = request.headers.authorization?.split(' ')?? [];
lämna tillbakatyp'Bärare'? tecken: odefinierad;
}
}
Koden implementerar en vakt, som anges i den officiella dokumentationen, för att skydda rutter och säkerställa att endast autentiserade användare med en giltig JWT-token kan komma åt dem.
Den extraherar JWT-tokenen från begäranshuvudet, verifierar dess äkthet med hjälp av JwtService, och tilldelar den avkodade nyttolasten till begära['användare'] egendom för vidare bearbetning. Om token saknas eller är ogiltig, kastar den en UnauthorizedException för att förhindra åtkomst till den skyddade rutten.
Skapa nu config.ts fil i samma katalog och lägg till koden nedan.
exporterakonst secretKey = {
hemlighet: "SEKTRET VÄRDE.",
};
Denna hemliga nyckel används för att signera och verifiera äktheten av JWT. Det är viktigt att lagra nyckelvärdet på ett säkert sätt för att förhindra obehörig åtkomst och skydda JWTs integritet.
Definiera API-kontrollern
Skapa en kontroller som hanterar API-slutpunkterna för användarautentisering.
nest g controller användarauth
Kopiera sedan koden som finns i denna GitHub-förvarsfil, och lägg till den i user-auth.controller.ts fil – den definierar slutpunkterna för användarregistrering, inloggning och hämtning av användardata. De UseGuards (AuthGuard) dekorator ingår för att upprätthålla autentisering för getUsers slutpunkt, vilket säkerställer att endast autentiserade användare ges åtkomst.
Uppdatera filen user-auth.module.ts
För att återspegla ändringarna som gjorts i projektet, uppdatera user-auth.module.ts fil för att konfigurera de nödvändiga modulerna, tjänsterna och kontrollerna för användarautentisering.
importera { Module, NestModule, MiddlewareConsumer } från'@nestjs/common';
importera { JwtModule } från'@nestjs/jwt';
importera { UserAuthController } från'./user-auth.controller';
importera { UserAuthService } från'./user-auth.service';
importera { MongooseModule } från'@nestjs/mongoose';
importera { UserSchema } från'./schemas/user-auth.schema';
importera { hemlig nyckel } från'./config';@Modul({
importer: [
MongooseModule.forFeature([{ namn: 'Användare', schema: UserSchema }]),
JwtModule.register({
hemlighet: secretKey.secret,
signOptions: { expiresIn: '1h' },
}),
],
kontroller: [UserAuthController],
leverantörer: [UserAuthService],
})
exporteraklass UserAuthModule redskap NestModule {
configure (konsument: MiddlewareConsumer) {
}
}
Slutligen, snurra upp utvecklingsservern och testa API-slutpunkterna med Postman.
npm körstart
Bygga säkra Nest.js REST API: er
Att bygga säkra Nest.js REST API: er kräver ett omfattande tillvägagångssätt som går längre än att bara lita på JWT: er för autentisering och auktorisering. Även om JWT är viktiga, är det lika viktigt att implementera ytterligare säkerhetsåtgärder.
Dessutom, genom att prioritera säkerhet i varje steg av API-utveckling, kan du säkerställa säkerheten för dina backend-system.