Utilisez l'architecture structurée de Nest pour créer des API REST sécurisées et efficaces.
Express.js est une excellente technologie pour créer des API REST sécurisées et robustes, cependant, il ne fournit pas de structure prédéfinie. Sa nature minimaliste vous permet de gérer des aspects essentiels tels que le routage, l'organisation du code et les mesures de sécurité, soit manuellement, soit en tirant parti des middleware et des bibliothèques disponibles.
En revanche, Nest.js, construit sur Express.js et Node.js, introduit une abstraction de niveau supérieur qui offre une structure claire, une approche robuste de l'organisation du code et une mise en œuvre simplifiée détails. Nest.js fournit essentiellement une architecture plus structurée pour créer des API et des services backend efficaces et sécurisés.
Configurer un projet Nest.js
Pour commencer, vous devez d'abord installer globalement la ligne de commande (CLI) de Nest.js en exécutant la commande ci-dessous :
npm i -g @nestjs/cli
Une fois l'installation terminée, continuez et créez un nouveau projet en exécutant :
nid nouveau nid-jwt-api
Ensuite, Nest.js CLI vous invitera à choisir un gestionnaire de packages pour installer les dépendances. Pour ce tutoriel, nous utiliserons npm, le gestionnaire de paquets de nœuds. Sélectionner npm et attendez que la CLI crée un projet Nest.js de base et installe tous les fichiers de configuration requis et les dépendances initiales requises pour exécuter l'application.
Une fois le projet configuré, accédez au répertoire du projet et démarrez le serveur de développement.
cd nest-jwt-api
démarrage de l'exécution npm
Enfin, exécutez la commande ci-dessous pour installer les packages que nous utiliserons pour ce projet.
npm installer mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt
Vous pouvez trouver le code de ce projet dans ce Référentiel GitHub.
Configurer la connexion à la base de données MongoDB
Configurer une base de données MongoDB localement ou configurer un cluster MongoDB sur le cloud. Après avoir configuré la base de données, copiez la chaîne URI de connexion à la base de données, créez un .env file dans le répertoire racine de notre dossier de projet et collez-y la chaîne de connexion :
MONGO_URI="chaîne de connexion"
Ensuite, mettez à jour le app.module.ts dans le src fichier de répertoire pour configurer Mongoose comme suit :
importer { Module } depuis'@nestjs/commun';
importer {ConfigModule} depuis'@nestjs/config';
importer {Module Mongoose} depuis'@nestjs/mangouste';
importer { Contrôleur d'application } depuis'./app.controller';
importer { AppService } depuis'./app.service';
importer { UserAuthModule } depuis'./user-auth/user-auth.module';@Module({
importations: [
ConfigModule.forRoot({
envFilePath: '.env',
estGlobal: vrai,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModule,
],
contrôleurs: [AppController],
fournisseurs: [AppService],
})
exporterclasse Module d'application {}
Le code fourni configure trois modules essentiels pour l'application Nest.js: ConfigModule pour la configuration de l'environnement, Module Mangouste pour établir la connexion MongoDB, et UserAuthModule pour l'authentification des utilisateurs. Veuillez noter qu'à ce stade, une erreur peut se produire puisque le UserAuthModule n'est pas encore défini, mais nous le créerons dans la section suivante.
Création du module d'authentification utilisateur
Pour conserver un code propre et bien organisé, créez un module d'authentification utilisateur en exécutant la commande suivante.
authentification de l'utilisateur du module nest g
L'outil CLI Nest.js génère automatiquement les fichiers de module requis. De plus, il mettra à jour le app.module.ts fichier, intégrant les modifications nécessaires liées au module d'authentification des utilisateurs.
Vous pouvez choisir de créer manuellement les principaux fichiers de configuration du projet, néanmoins, l'outil CLI simplifie ce processus en créant automatiquement les éléments requis, en plus de mettre à jour les modifications en conséquence dans le app.module.ts déposer.
Créer un schéma utilisateur
À l'intérieur du nouveau authentification utilisateur dossier dans le src répertoire, créez un nouveau schemas/user-auth.schema.ts fichier, et ajoutez le code suivant pour créer un schéma Mongoose pour le Utilisateur modèle
importer { Prop, Schema, SchemaFactory } depuis'@nestjs/mangouste';
importer { Document } depuis'mangouste';@Schéma({ horodatage: vrai })
exporterclasse Utilisateur {
@Soutenir()
nom d'utilisateur: chaîne;
@Soutenir()
mot de passe: chaîne;
}
exportertaper UserDocument = Utilisateur & Document ;
exporterconstante UserSchema = SchemaFactory.createForClass (Utilisateur);
Création du service d'authentification des utilisateurs
Créons maintenant le service d'authentification des utilisateurs qui gérera la logique d'authentification pour l'API REST en exécutant la commande ci-dessous :
authentification de l'utilisateur du service Nest G
Cette commande créera un user-auth.service.ts fichier dans le répertoire user-auth. Ouvrez ce fichier et mettez-le à jour avec le code suivant.
- Tout d'abord, effectuez les importations suivantes.
importer { Injectable, NotFoundException, Logger, UnauthorizedException } depuis'@nestjs/commun';
importer { InjectModel } depuis'@nestjs/mangouste';
importer { Modèle } depuis'mangouste';
importer { Utilisateur } depuis'./schemas/user-auth.schema';
importer * comme bcrypt depuis'bcrypt';
importer { JwtService } depuis'@nestjs/jwt'; - Ensuite, créez un UserAuthService classe qui encapsule la fonctionnalité d'enregistrement, de connexion et de récupération de toutes les routes de données utilisateur.
@Injectable()
exporterclasse Service d'authentification utilisateur {
privé enregistreur en lecture seule = nouveau Enregistreur (UserAuthService.name) ;
constructeur(@InjectModel(Nom d'utilisateur) privé userModel: modèle, privé jwtService: JwtService ) {}
asynchrone registerUser (nom d'utilisateur: chaîne, mot de passe: chaîne): Promessechaîne }> {
essayer {
constante hachage = attendre bcrypt.hash (mot de passe, 10);
attendrece.userModel.create({ nom d'utilisateur, mot de passe: hachage });
retour { message: 'Utilisateur enregistré avec succès' };
} attraper (erreur) {
lancernouveauErreur("Une erreur s'est produite lors de l'enregistrement de l'utilisateur");
}
}asynchrone loginUser (nom d'utilisateur: chaîne, mot de passe: chaîne): Promesse<chaîne> {
essayer {
constante utilisateur = attendrece.userModel.findOne({ nom d'utilisateur });
si (!utilisateur) {
lancernouveau Exception introuvable('Utilisateur non trouvé');
}
constante mot de passeMatch = attendre bcrypt.compare (mot de passe, utilisateur.motdepasse);
si (!passwordMatch) {
lancernouveau Exception non autorisée('Authentification invalide');
}
constante charge utile = { userId: user._id } ;
constante jeton = ce.jwtService.sign (charge utile);
retour jeton;
} attraper (erreur) {
console.log (erreur);
lancernouveau Exception non autorisée('Une erreur s'est produite lors de la connexion');
}
}
asynchrone getUsers(): Promesse
{
essayer {
constante utilisateurs = attendrece.userModel.find({});
retour utilisateurs;
} attraper (erreur) {
ce.logger.error(`Une erreur s'est produite lors de la récupération des utilisateurs: ${erreur.message}`);
lancernouveauErreur('Une erreur s'est produite lors de la récupération des utilisateurs');
}
}
}
Le UserAuthService La classe implémente la logique d'enregistrement, de connexion et de récupération des données utilisateur. Il utilise le userModel pour interagir avec la base de données et effectuer les actions requises, y compris le hachage du mot de passe pendant l'enregistrement, la validation des identifiants de connexion et enfin, la génération de jetons JWT après un succès authentification.
Implémentation de la protection d'authentification
Pour assurer la sécurité des ressources sensibles, il est crucial de limiter l'accès exclusivement aux utilisateurs autorisés. Ceci est réalisé en appliquant une mesure de sécurité qui impose la présence d'un JWT valide dans les demandes d'API ultérieures adressées aux points de terminaison protégés, dans ce cas, le utilisateurs itinéraire. Dans le authentification utilisateur répertoire, créez un nouveau auth.guard.ts fichier et ajoutez le code ci-dessous.
importer { CanActivate, ExecutionContext, Injectable, UnauthorizedException } depuis'@nestjs/commun';
importer { JwtService } depuis'@nestjs/jwt';
importer { Demande } depuis'exprimer';
importer { clef secrète } depuis'./config';@Injectable()
exporterclasse AuthGuard met en oeuvre Peut activer {
constructeur(privé jwtService: JwtService) {}
asynchrone canActivate (contexte: ExecutionContext): Promesse<booléen> {
constante demande = context.switchToHttp().getRequest();
constante jeton = ce.extractTokenFromHeader (demande);
si (!jeton) {
lancernouveau Exception non autorisée();
}
essayer {
constante charge utile = attendrece.jwtService.verifyAsync (jeton, {
secret: clésecrète.secret,
});
demande['utilisateur'] = charge utile ;
} attraper {
lancernouveau Exception non autorisée();
}
retourvrai;
}
privé extractTokenFromHeader (demande: Demande): chaîne | indéfini {
constante [taper, jeton] = request.headers.authorization?.split(' ')?? [];
retourtaper'Porteur'? jeton: indéfini;
}
}
Le code implémente une garde, comme spécifié dans la documentation officielle, pour protéger les routes et s'assurer que seuls les utilisateurs authentifiés avec un jeton JWT valide peuvent y accéder.
Il extrait le jeton JWT de l'en-tête de la requête, vérifie son authenticité à l'aide du JwtService, et attribue la charge utile décodée au demande['utilisateur'] propriété pour un traitement ultérieur. Si le jeton est manquant ou invalide, il lance une Exception non autorisée pour empêcher l'accès à la route protégée.
Maintenant, créez config.ts fichier dans le même répertoire et ajoutez le code ci-dessous.
exporterconstante clésecrète = {
secret: 'VALEUR SECRET.',
};
Cette clé secrète est utilisée pour signer et vérifier l'authenticité des JWT. Il est essentiel de stocker la valeur de clé en toute sécurité pour empêcher tout accès non autorisé et protéger l'intégrité des jetons JWT.
Définir le contrôleur d'API
Créez un contrôleur qui gère les points de terminaison d'API pour l'authentification des utilisateurs.
authentification de l'utilisateur du contrôleur nest g
Ensuite, copiez le code fourni dans ce Fichier de référentiel GitHub, et ajoutez-le au utilisateur-auth.controller.ts file—il définit les points de terminaison pour l'enregistrement, la connexion et la récupération des données utilisateur. Le Utiliser les Guards (AuthGuard) décorateur est inclus pour appliquer l'authentification pour le getUsers point de terminaison, en veillant à ce que seuls les utilisateurs authentifiés obtiennent l'accès.
Mettre à jour le fichier user-auth.module.ts
Pour refléter les modifications apportées au projet, mettez à jour le user-auth.module.ts pour configurer les modules, services et contrôleurs nécessaires à l'authentification des utilisateurs.
importer { Module, NestModule, MiddlewareConsumer } depuis'@nestjs/commun';
importer { JwtModule } depuis'@nestjs/jwt';
importer { UserAuthController } depuis'./user-auth.controller';
importer { UserAuthService } depuis'./user-auth.service';
importer {Module Mongoose} depuis'@nestjs/mangouste';
importer { Schéma utilisateur } depuis'./schemas/user-auth.schema';
importer { clef secrète } depuis'./config';@Module({
importations: [
MongooseModule.forFeature([{ nom: 'Utilisateur', schéma: UserSchema }]),
JwtModule.register({
secret: clésecrète.secret,
signOptions: { expireIn: '1h' },
}),
],
contrôleurs: [UserAuthController],
fournisseurs: [UserAuthService],
})
exporterclasse UserAuthModule met en oeuvre Nest Module {
configurer (consommateur: MiddlewareConsumer) {
}
}
Enfin, lancez le serveur de développement et testez les points de terminaison de l'API à l'aide de Postman.
démarrage de l'exécution npm
Création d'API REST Nest.js sécurisées
La création d'API REST Nest.js sécurisées nécessite une approche globale qui va au-delà de la simple dépendance aux JWT pour l'authentification et l'autorisation. Bien que les JWT soient importants, il est tout aussi crucial de mettre en œuvre des mesures de sécurité supplémentaires.
De plus, en donnant la priorité à la sécurité à chaque étape du développement de l'API, vous pouvez garantir la sécurité de vos systèmes backend.