Χρησιμοποιήστε τη δομημένη αρχιτεκτονική της Nest για να δημιουργήσετε ασφαλή και αποτελεσματικά API REST.

Το Express.js είναι μια εξαιρετική τεχνολογία για τη δημιουργία ασφαλών και ισχυρών API REST, ωστόσο, δεν παρέχει μια προκαθορισμένη δομή. Η μινιμαλιστική του φύση σάς επιτρέπει να χειρίζεστε βασικές πτυχές όπως η δρομολόγηση, η οργάνωση κώδικα και τα μέτρα ασφαλείας είτε χειροκίνητα είτε αξιοποιώντας το διαθέσιμο ενδιάμεσο λογισμικό και βιβλιοθήκες.

Αντίθετα, το Nest.js, χτισμένο πάνω από τα Express.js και Node.js, εισάγει μια αφαίρεση υψηλότερου επιπέδου που προσφέρει μια σαφή δομή, μια ισχυρή προσέγγιση οργάνωσης κώδικα και απλοποιημένη εφαρμογή Λεπτομέριες. Ουσιαστικά, το Nest.js παρέχει μια πιο δομημένη αρχιτεκτονική για τη δημιουργία αποτελεσματικών και ασφαλών backend API και υπηρεσιών.

Ρύθμιση έργου Nest.js

Για να ξεκινήσετε, πρέπει πρώτα να εγκαταστήσετε τη γραμμή εντολών (CLI) του Nest.js παγκοσμίως εκτελώντας την παρακάτω εντολή:

npm i -g @nestjs/cli

Μόλις ολοκληρωθεί η εγκατάσταση, προχωρήστε και δημιουργήστε ένα νέο έργο, εκτελώντας:

nest new nest-jwt-api

Στη συνέχεια, το Nest.js CLI θα σας ζητήσει να επιλέξετε έναν διαχειριστή πακέτων για να εγκαταστήσετε τις εξαρτήσεις. Για αυτό το σεμινάριο, θα χρησιμοποιήσουμε npm, το Node Package Manager. Επιλέγω npm και περιμένετε όσο το CLI δημιουργεί ένα βασικό έργο Nest.js και εγκαθιστά όλα τα απαιτούμενα αρχεία διαμόρφωσης και τις αρχικές εξαρτήσεις που απαιτούνται για την εκτέλεση της εφαρμογής.

Αφού ρυθμιστεί το έργο, μεταβείτε στον κατάλογο του έργου και ξεκινήστε τον διακομιστή ανάπτυξης.

cd nest-jwt-api
npm έναρξη λειτουργίας

Τέλος, εκτελέστε την παρακάτω εντολή για να εγκαταστήσετε τα πακέτα που θα χρησιμοποιήσουμε για αυτό το έργο.

npm εγκατάσταση mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt

Μπορείτε να βρείτε τον κωδικό αυτού του έργου σε αυτό Αποθετήριο GitHub.

Διαμόρφωση σύνδεσης βάσης δεδομένων MongoDB

Ρυθμίστε μια βάση δεδομένων MongoDB τοπικά ή διαμορφώστε ένα σύμπλεγμα MongoDB στο cloud. Αφού ρυθμίσετε τη βάση δεδομένων, αντιγράψτε τη συμβολοσειρά URI σύνδεσης βάσης δεδομένων, δημιουργήστε ένα .env αρχείο στον ριζικό κατάλογο του φακέλου του έργου μας και επικολλήστε τη συμβολοσειρά σύνδεσης:

MONGO_URI="συμβολοσειρά σύνδεσης"

Στη συνέχεια, ενημερώστε το app.module.ts στο src αρχείο καταλόγου για να διαμορφώσετε το Mongoose ως εξής:

εισαγωγή { Ενότητα } από'@nestjs/common';
εισαγωγή { ConfigModule } από'@nestjs/config';
εισαγωγή { MongooseModule } από'@nestjs/mongoose';
εισαγωγή { AppController } από"./app.controller";
εισαγωγή { AppService } από"./app.service";
εισαγωγή { UserAuthModule } από'./user-auth/user-auth.module';

@Μονάδα μέτρησης({
εισαγωγές: [
ConfigModule.forRoot({
envFilePath: ".env",
isGlobal: αληθής,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModule,
],
ελεγκτές: [AppController],
πάροχοι: [AppService],
})

εξαγωγήτάξη AppModule {}

Ο παρεχόμενος κώδικας διαμορφώνει τρεις βασικές ενότητες για την εφαρμογή Nest.js: ConfigModule για τη διαμόρφωση περιβάλλοντος, MongooseModule για τη δημιουργία της σύνδεσης MongoDB και UserAuthModule για έλεγχο ταυτότητας χρήστη. Λάβετε υπόψη ότι, σε αυτό το στάδιο, ενδέχεται να προκύψει σφάλμα καθώς το UserAuthModule δεν έχει οριστεί ακόμα, αλλά θα το δημιουργήσουμε στην επόμενη ενότητα.

Δημιουργία της μονάδας ελέγχου ταυτότητας χρήστη

Για να διατηρήσετε καθαρό και καλά οργανωμένο κώδικα, δημιουργήστε μια λειτουργική μονάδα ελέγχου ταυτότητας χρήστη εκτελώντας την ακόλουθη εντολή.

nest g module user-auth

Το εργαλείο Nest.js CLI δημιουργεί αυτόματα τα απαιτούμενα αρχεία λειτουργικής μονάδας. Επιπλέον, θα ενημερώσει το app.module.ts αρχείο, το οποίο ενσωματώνει τις απαραίτητες αλλαγές που σχετίζονται με τη μονάδα ελέγχου ταυτότητας χρήστη.

Μπορείτε να επιλέξετε να δημιουργήσετε τα κύρια αρχεία διαμόρφωσης έργου με μη αυτόματο τρόπο, ωστόσο, το εργαλείο CLI απλοποιεί αυτή τη διαδικασία δημιουργώντας αυτόματα τα απαιτούμενα στοιχεία, επιπλέον, ενημερώνοντας ανάλογα τις αλλαγές στο ο app.module.ts αρχείο.

Δημιουργήστε ένα σχήμα χρήστη

Μέσα στο νεοσύστατο χρήστη-auth φάκελο στο src κατάλογο, δημιουργήστε ένα νέο schemas/user-auth.schema.ts αρχείο και προσθέστε τον ακόλουθο κώδικα για να δημιουργήσετε ένα σχήμα Mongoose για το Χρήστης μοντέλο

εισαγωγή { Prop, Schema, SchemaFactory } από'@nestjs/mongoose';
εισαγωγή { Document } από'μαγκούστα';

@Σχήμα({ χρονικές σημάνσεις: αληθής })
εξαγωγήτάξη Χρήστης {
@Στήριγμα()
όνομα χρήστη: σειρά;
@Στήριγμα()
Κωδικός πρόσβασης: σειρά;
}

εξαγωγήτύπος UserDocument = Χρήστης & Έγγραφο;
εξαγωγήσυνθ UserSchema = SchemaFactory.createForClass (Χρήστης);

Δημιουργία της υπηρεσίας ελέγχου ταυτότητας χρήστη

Τώρα, ας δημιουργήσουμε την υπηρεσία ελέγχου ταυτότητας χρήστη που θα διαχειρίζεται τη λογική ελέγχου ταυτότητας για το REST API εκτελώντας την παρακάτω εντολή:

υπηρεσία nest g user-auth

Αυτή η εντολή θα δημιουργήσει ένα user-auth.service.ts αρχείο μέσα στον κατάλογο ταυτότητας χρήστη. Ανοίξτε αυτό το αρχείο και ενημερώστε το με τον ακόλουθο κώδικα.

  1. Πρώτα, κάντε τις ακόλουθες εισαγωγές.
    εισαγωγή { Injectable, NotFoundException, Logger, UnauthorizedException } από'@nestjs/common';
    εισαγωγή { InjectModel } από'@nestjs/mongoose';
    εισαγωγή { Μοντέλο } από'μαγκούστα';
    εισαγωγή { Χρήστης } από"./schemas/user-auth.schema";
    εισαγωγή * όπως και bcrypt από'bcrypt';
    εισαγωγή { JwtService } από'@nestjs/jwt';
  2. Στη συνέχεια, δημιουργήστε ένα UserAuthService κλάση που ενσωματώνει τη λειτουργικότητα για την εγγραφή χρήστη, τη σύνδεση και την ανάκτηση όλων των διαδρομών δεδομένων χρήστη.
@Ενέσιμα()
εξαγωγήτάξη UserAuthService {
ιδιωτικός καταγραφέας μόνο για ανάγνωση = νέος Logger (UserAuthService.name);
κατασκευαστής(@InjectModel(Όνομα χρήστη) ιδιωτικός userModel: Μοντέλο, ιδιωτικός jwtService: JwtService) {}

ασυγχρονισμός registerUser (όνομα χρήστη: σειρά, Κωδικός πρόσβασης: σειρά): Υπόσχεσησειρά }> {
δοκιμάστε {
συνθ κατακερματισμός = αναμένω bcrypt.hash (κωδικός πρόσβασης, 10);
αναμένωΑυτό.userModel.create({ όνομα χρήστη, κωδικός πρόσβασης: κατακερματισμός });
ΕΠΙΣΤΡΟΦΗ { μήνυμα: "Ο χρήστης εγγράφηκε με επιτυχία" };
} σύλληψη (λάθος) {
βολήνέοςΛάθος("Παρουσιάστηκε σφάλμα κατά την εγγραφή του χρήστη");
}
 }

ασυγχρονισμός loginUser (όνομα χρήστη: σειρά, Κωδικός πρόσβασης: σειρά): Υπόσχεση<σειρά> {
δοκιμάστε {
συνθ χρήστης = αναμένωΑυτό.userModel.findOne({ όνομα χρήστη });
αν (!χρήστης) {
βολήνέος NotFoundException('Ο χρήστης δεν βρέθηκε');
}
συνθ κωδικός Ταίριασμα = αναμένω bcrypt.compare (password, user.password);
αν (!passwordMatch) {
βολήνέος Μη εξουσιοδοτημένηΕξαίρεση("Μη έγκυρα διαπιστευτήρια σύνδεσης");
}
συνθ ωφέλιμο φορτίο = {userId: user._id };
συνθ μάρκα = Αυτό.jwtService.sign (ωφέλιμο φορτίο);
ΕΠΙΣΤΡΟΦΗ ένδειξη;
} σύλληψη (λάθος) {
κονσόλα.log (σφάλμα);
βολήνέος Μη εξουσιοδοτημένηΕξαίρεση("Παρουσιάστηκε σφάλμα κατά τη σύνδεση");
}
}

ασυγχρονισμός getUsers(): Υπόσχεση {
δοκιμάστε {
συνθ χρήστες = αναμένωΑυτό.userModel.find({});
ΕΠΙΣΤΡΟΦΗ χρήστες·
} σύλληψη (λάθος) {
Αυτό.logger.error(`Παρουσιάστηκε σφάλμα κατά την ανάκτηση χρηστών: ${error.message}`);
βολήνέοςΛάθος("Παρουσιάστηκε σφάλμα κατά την ανάκτηση χρηστών");
}
}
}

ο UserAuthService Η class υλοποιεί τη λογική της εγγραφής χρήστη, της σύνδεσης και της ανάκτησης δεδομένων χρήστη. Χρησιμοποιεί το μοντέλο χρήστη για αλληλεπίδραση με τη βάση δεδομένων και εκτέλεση των απαιτούμενων ενεργειών, συμπεριλαμβανομένου του κατακερματισμού του κωδικού πρόσβασης κατά τη διάρκεια εγγραφή, επικύρωση των διαπιστευτηρίων σύνδεσης και, τέλος, δημιουργία κουπονιών JWT μετά από επιτυχία αυθεντικοποίηση.

Εφαρμογή του Authentication Guard

Για να διασφαλιστεί η ασφάλεια των ευαίσθητων πόρων, είναι σημαντικό να περιοριστεί η πρόσβαση αποκλειστικά σε εξουσιοδοτημένους χρήστες. Αυτό επιτυγχάνεται με την επιβολή ενός μέτρου ασφαλείας που επιβάλλει την παρουσία ενός έγκυρου JWT σε επόμενα αιτήματα API που γίνονται σε προστατευμένα τελικά σημεία, σε αυτήν την περίπτωση, τα χρήστες Διαδρομή. Στο χρήστη-auth κατάλογο, δημιουργήστε ένα νέο αυθ.φύλακας.τσ αρχείο και προσθέστε τον παρακάτω κώδικα.

εισαγωγή { CanActivate, ExecutionContext, Injectable, UnauthorizedException } από'@nestjs/common';
εισαγωγή { JwtService } από'@nestjs/jwt';
εισαγωγή { Αίτηση } από'εξπρές';
εισαγωγή { μυστικό κλειδί } από'./config';

@Ενέσιμα()
εξαγωγήτάξη AuthGuard υλοποιεί CanActivate {
κατασκευαστής(ιδιωτικός jwtService: JwtService) {}

ασυγχρονισμός canActivate (πλαίσιο: ExecutionContext): Υπόσχεση<boolean> {
συνθ request = context.switchToHttp().getRequest();
συνθ μάρκα = Αυτό.extractTokenFromHeader (αίτημα);
αν (!token) {
βολήνέος UnauthorizedException();
}
δοκιμάστε {
συνθ ωφέλιμο φορτίο = αναμένωΑυτό.jwtService.verifyAsync (token, {
μυστικό: secretKey.secret,
});
αίτηση['χρήστης'] = ωφέλιμο φορτίο;
} σύλληψη {
βολήνέος UnauthorizedException();
}
ΕΠΙΣΤΡΟΦΗαληθής;
}
ιδιωτικός extractTokenFromHeader (αίτημα: Αίτημα): σειρά | απροσδιόριστος {
συνθ [τύπος, token] = request.headers.authorization?.split(' ')?? [];
ΕΠΙΣΤΡΟΦΗτύπος'Φορέας'? ένδειξη: απροσδιόριστος;
}
}

Ο κώδικας υλοποιεί α φρουρά, όπως ορίζεται στην επίσημη τεκμηρίωση, για την προστασία των διαδρομών και τη διασφάλιση ότι μόνο οι πιστοποιημένοι χρήστες με έγκυρο διακριτικό JWT έχουν πρόσβαση σε αυτές.

Εξάγει το διακριτικό JWT από την κεφαλίδα αιτήματος, επαληθεύει την αυθεντικότητά του χρησιμοποιώντας το JwtService, και εκχωρεί το αποκωδικοποιημένο ωφέλιμο φορτίο στο αίτημα['χρήστης'] ακίνητο για περαιτέρω επεξεργασία. Εάν το διακριτικό λείπει ή είναι άκυρο, ρίχνει ένα Unauthorized Exception για να αποτρέψετε την πρόσβαση στην προστατευμένη διαδρομή.

Τώρα, δημιουργήστε config.ts αρχείο στον ίδιο κατάλογο και προσθέστε τον παρακάτω κώδικα.

εξαγωγήσυνθ μυστικό κλειδί = {
μυστικό: 'SECTRET VALUE.',
};

Αυτό το μυστικό κλειδί χρησιμοποιείται για την υπογραφή και την επαλήθευση της γνησιότητας των JWT. Είναι απαραίτητο να αποθηκεύσετε την τιμή κλειδιού με ασφάλεια για να αποτρέψετε τη μη εξουσιοδοτημένη πρόσβαση και να προστατεύσετε την ακεραιότητα των JWT.

Ορίστε τον ελεγκτή API

Δημιουργήστε έναν ελεγκτή που χειρίζεται τα τελικά σημεία API για έλεγχο ταυτότητας χρήστη.

nest g ελεγκτής χρήστη-auth

Στη συνέχεια, αντιγράψτε τον κωδικό που παρέχεται σε αυτό Αρχείο αποθετηρίου GitHubκαι προσθέστε το στο user-auth.controller.ts αρχείο—καθορίζει τα τελικά σημεία για την εγγραφή χρήστη, τη σύνδεση και την ανάκτηση δεδομένων χρήστη. ο UseGuards (AuthGuard) διακοσμητής περιλαμβάνεται για την επιβολή ελέγχου ταυτότητας για το getUsers τελικό σημείο, διασφαλίζοντας ότι παρέχεται πρόσβαση μόνο σε πιστοποιημένους χρήστες.

Ενημερώστε το αρχείο user-auth.module.ts

Για να αντικατοπτρίσετε τις αλλαγές που έγιναν στο έργο, ενημερώστε το user-auth.module.ts αρχείο για να διαμορφώσετε τις απαραίτητες μονάδες, υπηρεσίες και ελεγκτές για τον έλεγχο ταυτότητας χρήστη.

εισαγωγή { Module, NestModule, MiddlewareConsumer } από'@nestjs/common';
εισαγωγή { JwtModule } από'@nestjs/jwt';
εισαγωγή { UserAuthController } από"./user-auth.controller";
εισαγωγή { UserAuthService } από"./user-auth.service";
εισαγωγή { MongooseModule } από'@nestjs/mongoose';
εισαγωγή { User Schema } από"./schemas/user-auth.schema";
εισαγωγή { μυστικό κλειδί } από'./config';

@Μονάδα μέτρησης({
εισαγωγές: [
MongooseModule.forFeature([{ name: 'Χρήστης', σχήμα: UserSchema }]),
JwtModule.register({
μυστικό: secretKey.secret,
signOptions: { expiresIn: '1 ώρα' },
}),
],
ελεγκτές: [UserAuthController],
πάροχοι: [UserAuthService],
})

εξαγωγήτάξη UserAuthModule υλοποιεί NestModule {
configure (consumer: MiddlewareConsumer) {
}
}

Τέλος, περιστρέψτε τον διακομιστή ανάπτυξης και δοκιμάστε τα τελικά σημεία του API χρησιμοποιώντας το Postman.

npm έναρξη λειτουργίας

Δημιουργία Secure Nest.js REST API

Η δημιουργία ασφαλών Nest.js REST API απαιτεί μια ολοκληρωμένη προσέγγιση που ξεπερνά το να βασίζεσαι απλώς σε JWT για έλεγχο ταυτότητας και εξουσιοδότηση. Ενώ τα JWT είναι σημαντικά, είναι εξίσου σημαντικό να εφαρμοστούν πρόσθετα μέτρα ασφαλείας.

Επιπλέον, δίνοντας προτεραιότητα στην ασφάλεια σε κάθε στάδιο της ανάπτυξης API, μπορείτε να διασφαλίσετε την ασφάλεια των συστημάτων υποστήριξης σας.