Sfrutta l'architettura strutturata di Nest per creare API REST sicure ed efficienti.
Express.js è un'ottima tecnologia per la creazione di API REST sicure e robuste, tuttavia non fornisce una struttura predefinita. La sua natura minimalista consente di gestire aspetti essenziali come il routing, l'organizzazione del codice e le misure di sicurezza manualmente o sfruttando il middleware e le librerie disponibili.
Al contrario, Nest.js, basato su Express.js e Node.js, introduce un'astrazione di livello superiore che offre una struttura chiara, un solido approccio all'organizzazione del codice e un'implementazione semplificata dettagli. Essenzialmente, Nest.js fornisce un'architettura più strutturata per la creazione di API e servizi back-end efficienti e sicuri.
Configurazione di un progetto Nest.js
Per iniziare, devi prima installare la riga di comando (CLI) di Nest.js a livello globale eseguendo il comando seguente:
npm i -g @nestjs/cli
Una volta completata l'installazione, vai avanti e crea un nuovo progetto, eseguendo:
nido nuovo nido-jwt-api
Successivamente, l'interfaccia a riga di comando di Nest.js ti chiederà di scegliere un gestore di pacchetti per installare le dipendenze. Per questo tutorial, useremo npm, il Node Package Manager. Selezionare npm e attendi che l'interfaccia a riga di comando crei un progetto Nest.js di base e installi tutti i file di configurazione richiesti e le dipendenze iniziali richieste per eseguire l'applicazione.
Dopo aver configurato il progetto, vai alla directory del progetto e avvia il server di sviluppo.
cd nest-jwt-api
avvio della corsa npm
Infine, esegui il comando seguente per installare i pacchetti che useremo per questo progetto.
npm installa mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt
Puoi trovare il codice di questo progetto in questo Deposito GitHub.
Configura la connessione al database MongoDB
Configura un database MongoDB in locale O configurare un cluster MongoDB sul cloud. Dopo aver configurato il database, copiare la stringa URI di connessione al database, creare un file .env file nella directory principale della nostra cartella del progetto e incollare la stringa di connessione:
MONGO_URI="stringa di connessione"
Successivamente, aggiorna il file app.module.ts nel src file di directory per configurare Mongoose come segue:
importare { Modulo } da'@nestjs/comune';
importare {ConfigModule} da'@nestjs/config';
importare {Modulo mangusta} da'@nestjs/mangusta';
importare {Controller dell'applicazione} da'./app.controllore';
importare {Servizio app} da'./servizio.app';
importare { UserAuthModule } da'./autenticazione-utente/autenticazione-utente.module';@Modulo({
importazioni: [
ConfigModule.forRoot({
envFilePath: '.env',
è globale: VERO,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModule,
],
controller: [AppController],
fornitori: [AppService],
})
esportareclasse Modulo applicazione {}
Il codice fornito configura tre moduli essenziali per l'applicazione Nest.js: ConfigModule per la configurazione dell'ambiente, MangustaModulo per stabilire la connessione MongoDB e UserAuthModule per l'autenticazione dell'utente. Si prega di notare che, in questa fase, potrebbe verificarsi un errore poiché il file UserAuthModule non è ancora definito, ma lo creeremo nella prossima sezione.
Creazione del modulo di autenticazione utente
Per mantenere un codice pulito e ben organizzato, crea un modulo di autenticazione utente eseguendo il comando seguente.
modulo nest g user-auth
Lo strumento CLI Nest.js genera automaticamente i file del modulo richiesti. Inoltre, aggiornerà il file app.module.ts file, incorporando le modifiche necessarie relative al modulo di autenticazione dell'utente.
Puoi scegliere di creare manualmente i file di configurazione del progetto principale, tuttavia, lo strumento CLI semplifica questo processo creando automaticamente gli elementi richiesti, oltre ad aggiornare le modifiche di conseguenza in IL app.module.ts file.
Crea uno schema utente
All'interno del nuovo creato autenticazione utente cartella in src directory, creane una nuova schemi/user-auth.schema.ts file e aggiungere il codice seguente per creare uno schema Mongoose per il file Utente modello
importare { Prop, Schema, SchemaFactory } da'@nestjs/mangusta';
importare { Documento } da'mangusta';@Schema({ timestamp: VERO })
esportareclasse Utente {
@Puntello()
nome utente: corda;
@Puntello()
parola d'ordine: corda;
}
esportaretipo UserDocument = Utente & Documento;
esportarecost UserSchema = SchemaFactory.createForClass (Utente);
Creazione del servizio di autenticazione utente
Ora creiamo il servizio di autenticazione utente che gestirà la logica di autenticazione per l'API REST eseguendo il comando seguente:
autenticazione utente del servizio nest g
Questo comando creerà un file utente-auth.service.ts file all'interno della directory user-auth. Apri questo file e aggiornalo con il seguente codice.
- Innanzitutto, effettua le seguenti importazioni.
importare { Injectable, NotFoundException, Logger, UnauthorizedException } da'@nestjs/comune';
importare {IniettareModello} da'@nestjs/mangusta';
importare { Modello } da'mangusta';
importare { Utente } da'./schemi/user-auth.schema';
importare * COME bcrypt da'bcrypt';
importare { JwtServizio } da'@nestjs/jwt'; - Quindi, crea un UserAuthService classe che incapsula la funzionalità per la registrazione dell'utente, l'accesso e il recupero di tutte le route di dati dell'utente.
@Iniettabile()
esportareclasse UserAuthService {
privato logger di sola lettura = nuovo Logger (UserAuthService.name);
costruttore(@InjectModel(Nome utente) privato userModel: modello, privato jwtService: JwtService ) {}
asincrono registerUser (nome utente: corda, parola d'ordine: corda): Prometterecorda }> {
Tentativo {
cost hash = aspetta bcrypt.hash (password, 10);
aspettaQuesto.userModel.create({ username, password: hash });
ritorno { Messaggio: 'Utente registrato con successo' };
} presa (errore) {
gettarenuovoErrore('Si è verificato un errore durante la registrazione dell'utente');
}
}asincrono loginUtente (nome utente: corda, parola d'ordine: corda): Promettere<corda> {
Tentativo {
cost utente = aspettaQuesto.userModel.findOne({ username });
Se (!utente) {
gettarenuovo NotFoundException('Utente non trovato');
}
cost passwordMatch = aspetta bcrypt.compare (password, utente.password);
Se (!passwordMatch) {
gettarenuovo Eccezione non autorizzata('Credenziali di accesso non valide');
}
cost carico utile = { userId: user._id };
cost gettone = Questo.jwtService.sign (carico utile);
ritorno gettone;
} presa (errore) {
consolare.log (errore);
gettarenuovo Eccezione non autorizzata('Si è verificato un errore durante l'accesso');
}
}
asincrono getUtenti(): Promettere
{
Tentativo {
cost utenti = aspettaQuesto.userModel.find({});
ritorno utenti;
} presa (errore) {
Questo.logger.errore(`Si è verificato un errore durante il recupero degli utenti: ${errore.messaggio}`);
gettarenuovoErrore("Si è verificato un errore durante il recupero degli utenti");
}
}
}
IL UserAuthService class implementa la logica della registrazione dell'utente, del login e del recupero dei dati dell'utente. Utilizza il userModel per interagire con il database ed eseguire le azioni richieste, incluso l'hashing della password durante registrazione, convalida delle credenziali di accesso e, infine, generazione di token JWT dopo l'esito positivo autenticazione.
Implementazione della protezione dell'autenticazione
Per garantire la sicurezza delle risorse sensibili, è fondamentale limitare l'accesso esclusivamente agli utenti autorizzati. Ciò si ottiene applicando una misura di sicurezza che imponga la presenza di un JWT valido nelle successive richieste API effettuate agli endpoint protetti, in questo caso il utenti itinerario. Nel autenticazione utente directory, creane una nuova auth.guard.ts file e aggiungere il codice qui sotto.
importare {CanActivate, ExecutionContext, Injectable, UnauthorizedException} da'@nestjs/comune';
importare { JwtServizio } da'@nestjs/jwt';
importare { Richiesta } da'esprimere';
importare { chiave segreta } da'./config';@Iniettabile()
esportareclasse Authguard implementa CanActivate {
costruttore(privato jwtService: JwtService) {}
asincrono canActivate (contesto: ExecutionContext): Promettere<booleano> {
cost request = context.switchToHttp().getRequest();
cost gettone = Questo.extractTokenFromHeader (richiesta);
Se (!gettone) {
gettarenuovo UnauthorizedException();
}
Tentativo {
cost carico utile = aspettaQuesto.jwtService.verifyAsync (token, {
segreto: secretKey.secret,
});
richiesta['utente'] = carico utile;
} presa {
gettarenuovo UnauthorizedException();
}
ritornoVERO;
}
privato extractTokenFromHeader (richiesta: Richiesta): corda | non definito {
cost [tipo, token] = request.headers.authorization?.split(' ')?? [];
ritornotipo'Portatore'? gettone: non definito;
}
}
Il codice implementa a guardia, come specificato nella documentazione ufficiale, per proteggere i percorsi e garantire che solo gli utenti autenticati con un token JWT valido possano accedervi.
Estrae il token JWT dall'intestazione della richiesta, ne verifica l'autenticità utilizzando il file JwtService, e assegna il payload decodificato al file richiesta['utente'] proprietà per ulteriori elaborazioni. Se il token è mancante o non valido, lancia un Eccezione non autorizzata per impedire l'accesso al percorso protetto.
Ora, crea config.ts file nella stessa directory e aggiungi il codice qui sotto.
esportarecost chiave segreta = {
segreto: 'VALORE SEGRETO.',
};
Questa chiave segreta viene utilizzata per firmare e verificare l'autenticità dei JWT. È essenziale archiviare il valore della chiave in modo sicuro per impedire l'accesso non autorizzato e proteggere l'integrità dei JWT.
Definire il controller API
Crea un controller che gestisca gli endpoint API per l'autenticazione dell'utente.
autenticazione utente del controller nest g
Quindi, copia il codice fornito in questo File del repository GitHube aggiungerlo al utente-auth.controller.ts file: definisce gli endpoint per la registrazione dell'utente, l'accesso e il recupero dei dati dell'utente. IL UseGuard (AuthGuard) decoratore è incluso per imporre l'autenticazione per il file getUtenti endpoint, assicurando che solo gli utenti autenticati abbiano accesso.
Aggiorna il file user-auth.module.ts
Per riflettere le modifiche apportate al progetto, aggiornare il file utente-auth.module.ts file per configurare i moduli, i servizi e i controller necessari per l'autenticazione dell'utente.
importare { Module, NestModule, MiddlewareConsumer } da'@nestjs/comune';
importare { Modulo Jwt } da'@nestjs/jwt';
importare { ControllerAuth utente } da'./utente-auth.controller';
importare {UserAuthService} da'./user-auth.servizio';
importare {Modulo mangusta} da'@nestjs/mangusta';
importare {Schema utente} da'./schemi/user-auth.schema';
importare { chiave segreta } da'./config';@Modulo({
importazioni: [
MongooseModule.forFeature([{ nome: 'Utente', schema: UserSchema }]),
JwtModule.register({
segreto: secretKey.secret,
signOptions: {cadeIn: '1h' },
}),
],
controllori: [UserAuthController],
fornitori: [UserAuthService],
})
esportareclasse UserAuthModule implementa NestModule {
configure (consumatore: MiddlewareConsumer) {
}
}
Infine, avvia il server di sviluppo e testa gli endpoint API utilizzando Postman.
avvio della corsa npm
Creazione di API REST Nest.js sicure
La creazione di API REST Nest.js sicure richiede un approccio completo che vada oltre il semplice affidamento ai JWT per l'autenticazione e l'autorizzazione. Sebbene i JWT siano importanti, è altrettanto fondamentale implementare ulteriori misure di sicurezza.
Inoltre, assegnando la priorità alla sicurezza in ogni fase dello sviluppo dell'API, puoi garantire la sicurezza dei tuoi sistemi di back-end.