Wykorzystaj ustrukturyzowaną architekturę Nest do tworzenia bezpiecznych i wydajnych interfejsów API REST.
Express.js to świetna technologia do tworzenia bezpiecznych i niezawodnych interfejsów API REST, jednak nie zapewnia predefiniowanej struktury. Jego minimalistyczny charakter umożliwia obsługę podstawowych aspektów, takich jak routing, organizacja kodu i środki bezpieczeństwa, ręcznie lub przy użyciu dostępnego oprogramowania pośredniczącego i bibliotek.
Natomiast Nest.js, zbudowany na bazie Express.js i Node.js, wprowadza abstrakcję wyższego poziomu który oferuje przejrzystą strukturę, solidne podejście do organizacji kodu i uproszczoną implementację Detale. Zasadniczo Nest.js zapewnia bardziej ustrukturyzowaną architekturę do tworzenia wydajnych i bezpiecznych interfejsów API i usług zaplecza.
Konfigurowanie projektu Nest.js
Aby rozpocząć, musisz najpierw globalnie zainstalować wiersz poleceń (CLI) Nest.js, uruchamiając poniższe polecenie:
npm i -g @nestjs/cli
Po zakończeniu instalacji kontynuuj i utwórz nowy projekt, uruchamiając:
zagnieżdż nowe gniazdo-jwt-api
Następnie Nest.js CLI wyświetli monit o wybranie menedżera pakietów do zainstalowania zależności. W tym samouczku użyjemy npm, menedżer pakietów węzłów. Wybierać np i poczekaj, aż CLI utworzy podstawowy projekt Nest.js i zainstaluje wszystkie wymagane pliki konfiguracyjne i początkowe zależności wymagane do uruchomienia aplikacji.
Po skonfigurowaniu projektu przejdź do katalogu projektu i uruchom serwer deweloperski.
cd gniazdo-jwt-api
start biegu npm
Na koniec uruchom poniższe polecenie, aby zainstalować pakiety, których użyjemy w tym projekcie.
npm zainstaluj mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt
Możesz znaleźć kod tego projektu w this Repozytorium GitHub.
Skonfiguruj połączenie z bazą danych MongoDB
Skonfiguruj lokalnie bazę danych MongoDB Lub skonfiguruj klaster MongoDB w chmurze. Po skonfigurowaniu bazy danych skopiuj ciąg URI połączenia z bazą danych, utwórz plik .env plik w katalogu głównym naszego folderu projektu i wklej parametry połączenia:
MONGO_URI="ciąg połączenia"
Następnie zaktualizuj plik aplikacja.moduł.ts w źródło katalog, aby skonfigurować Mongoose w następujący sposób:
import { Moduł } z'@nestjs/wspólne';
import { Moduł konfiguracyjny } z'@nestjs/config';
import {Moduł Mongoose} z'@nestjs/mangusta';
import { Kontroler aplikacji } z„./kontroler aplikacji”;
import { Usługa aplikacji } z„./usługa.aplikacji”;
import { UserAuthModule } z„./uwierzytelnianie-użytkownika/moduł-uwierzytelniania-użytkownika”;@Moduł({
import: [
ConfigModule.forRoot({
Ścieżka do pliku env: '.env',
jestGlobalny: PRAWDA,
}),
MongooseModule.forRoot (process.env. MONGO_URI),
UserAuthModuł,
],
kontrolery: [Kontroler aplikacji],
dostawcy: [AppService],
})
eksportklasa Moduł aplikacji {}
Dostarczony kod konfiguruje trzy podstawowe moduły dla aplikacji Nest.js: Moduł konfiguracji do konfiguracji środowiska, MangustaModuł do ustanowienia połączenia MongoDB i UserAuthModule do uwierzytelniania użytkownika. Należy pamiętać, że na tym etapie może wystąpić błąd, ponieważ plik UserAuthModule nie jest jeszcze zdefiniowany, ale utworzymy go w następnej sekcji.
Tworzenie modułu uwierzytelniania użytkownika
Aby zachować czysty i dobrze zorganizowany kod, utwórz moduł uwierzytelniania użytkownika, uruchamiając następujące polecenie.
zagnieżdżanie autoryzacji użytkownika modułu g
Narzędzie Nest.js CLI automatycznie generuje wymagane pliki modułów. Dodatkowo zaktualizuje aplikacja.moduł.ts plik zawierający niezbędne zmiany związane z modułem autoryzacji użytkownika.
Możesz zdecydować się na ręczne utworzenie głównych plików konfiguracyjnych projektu, niemniej jednak narzędzie CLI upraszcza ten proces, automatycznie tworząc wymagane elementy, a także odpowiednio aktualizując zmiany w the aplikacja.moduł.ts plik.
Utwórz schemat użytkownika
Wewnątrz nowo utworzonego autoryzacja użytkownika folder w źródło katalogu, utwórz nowy schemas/user-auth.schema.ts plik i dodaj następujący kod, aby utworzyć schemat Mongoose dla Użytkownik Model
import { Rekwizyt, Schemat, Fabryka Schematów} z'@nestjs/mangusta';
import { Dokument } z'mangusta';@Schemat({ znaczniki czasu: PRAWDA })
eksportklasa Użytkownik {
@Rekwizyt()
nazwa użytkownika: strunowy;
@Rekwizyt()
hasło: strunowy;
}
eksporttyp UserDocument = Użytkownik i dokument;
eksportkonst UserSchema = SchemaFactory.createForClass (użytkownik);
Tworzenie usługi uwierzytelniania użytkownika
Teraz utwórzmy usługę uwierzytelniania użytkowników, która będzie zarządzać logiką uwierzytelniania dla interfejsu API REST, uruchamiając poniższe polecenie:
uwierzytelnianie użytkownika usługi g
To polecenie utworzy plik user-auth.service.ts plik w katalogu user-auth. Otwórz ten plik i zaktualizuj go za pomocą następującego kodu.
- Najpierw wykonaj następujące importy.
import { Do wstrzyknięcia, NotFoundException, Logger, UnauthorizedException } z'@nestjs/wspólne';
import {Model wstrzykiwania} z'@nestjs/mangusta';
import { Model } z'mangusta';
import { Użytkownik } z„./schemas/user-auth.schema”;
import * Jak bcrypt z„bszyfruj”;
import {JwtService} z'@nestjs/jwt'; - Następnie utwórz a UserAuthService klasa, która hermetyzuje funkcjonalność rejestracji użytkownika, logowania i pobierania wszystkich tras danych użytkownika.
@Do wstrzykiwań()
eksportklasa UserAuthService {
prywatny rejestrator tylko do odczytu = nowy Rejestrator (UserAuthService.name);
konstruktor(@InjectModel(Nazwa użytkownika) prywatny Model użytkownika: model, prywatny jwtService: JwtService ) {}
asynchroniczny registerUser (nazwa użytkownika: strunowy, hasło: strunowy): Obietnicastrunowy }> {
próbować {
konst hash = czekać na bcrypt.hash (hasło, 10);
czekać naTen.userModel.create({ nazwa użytkownika, hasło: hash });
powrót { wiadomość: „Użytkownik zarejestrowany pomyślnie” };
} złapać (błąd) {
rzucićnowyBłąd(„Wystąpił błąd podczas rejestracji użytkownika”);
}
}asynchroniczny loginUser (nazwa użytkownika: strunowy, hasło: strunowy): Obietnica<strunowy> {
próbować {
konst użytkownik = czekać naTen.userModel.findOne({ nazwa użytkownika });
Jeśli (!użytkownik) {
rzucićnowy Nieznaleziony wyjątek('Użytkownik nie znaleziony');
}
konst dopasowanie hasła = czekać na bcrypt.compare (hasło, hasło.użytkownika);
Jeśli (!pasujące hasło) {
rzucićnowy Nieautoryzowany wyjątek ('Nieprawidłowe dane logowania');
}
konst ładunek = { userId: user._id };
konst token = Ten.jwtService.sign (ładunek);
powrót znak;
} złapać (błąd) {
konsola.log (błąd);
rzucićnowy Nieautoryzowany wyjątek ('Wystąpił błąd podczas logowania');
}
}
asynchroniczny pobierzUżytkownicy(): Obietnica
{
próbować {
konst użytkownicy = czekać naTen.userModel.find({});
powrót użytkownicy;
} złapać (błąd) {
Ten.logger.błąd(`Wystąpił błąd podczas pobierania użytkowników: ${komunikat o błędzie}`);
rzucićnowyBłąd(„Wystąpił błąd podczas pobierania użytkowników”);
}
}
}
The UserAuthService klasa implementuje logikę rejestracji użytkownika, logowania i pobierania danych użytkownika. Używa model użytkownika do interakcji z bazą danych i wykonywania wymaganych działań, w tym mieszania hasła podczas rejestracja, sprawdzanie poprawności danych logowania i wreszcie generowanie tokenów JWT po pomyślnym zakończeniu uwierzytelnianie.
Wdrażanie strażnika uwierzytelniania
Dla zapewnienia bezpieczeństwa wrażliwych zasobów kluczowe jest ograniczenie dostępu wyłącznie do uprawnionych użytkowników. Osiąga się to poprzez wymuszenie środka bezpieczeństwa, który nakazuje obecność prawidłowego JWT w kolejnych żądaniach API wysyłanych do chronionych punktów końcowych, w tym przypadku użytkownicy trasa. w autoryzacja użytkownika katalogu, utwórz nowy authguard.ts plik i dodaj poniższy kod.
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } z'@nestjs/wspólne';
import {JwtService} z'@nestjs/jwt';
import { Wniosek } z'wyrazić';
import { sekretny klucz } z'./konfiguracja';@Do wstrzykiwań()
eksportklasa AuthGuard przybory MożeAktywować {
konstruktor(prywatny jwtService: JwtService) {}
asynchroniczny canActivate (kontekst: ExecutionContext): Obietnica<logiczna> {
konst żądanie = context.switchToHttp().getRequest();
konst token = Ten.extractTokenFromHeader (żądanie);
Jeśli (!token) {
rzucićnowy Nieautoryzowany wyjątek();
}
próbować {
konst ładowność = czekać naTen.jwtService.verifyAsync (token, {
sekret: tajnyKlucz.tajny,
});
wniosek['użytkownik'] = ładowność;
} złapać {
rzucićnowy Nieautoryzowany wyjątek();
}
powrótPRAWDA;
}
prywatny extractTokenFromHeader (żądanie: Żądanie): strunowy | nieokreślony {
konst [typ, token] = request.headers.authorization?.split(' ')?? [];
powróttyp'Okaziciel'? znak: nieokreślony;
}
}
Kod implementuje a strażnik, jak określono w oficjalnej dokumentacji, aby chronić trasy i zapewnić dostęp do nich tylko uwierzytelnionym użytkownikom z ważnym tokenem JWT.
Wyodrębnia token JWT z nagłówka żądania, weryfikuje jego autentyczność za pomocą JwtService, i przypisuje zdekodowany ładunek do prośba['użytkownik'] własności do dalszego przetwarzania. Jeśli brakuje żetonu lub jest on nieprawidłowy, zgłaszany jest błąd Nieautoryzowany wyjątek aby uniemożliwić dostęp do chronionej trasy.
Teraz stwórz config.ts plik w tym samym katalogu i dodaj poniższy kod.
eksportkonst tajny klucz = {
sekret: „TAJNA WARTOŚĆ”.,
};
Ten tajny klucz służy do podpisywania i weryfikowania autentyczności tokenów JWT. Konieczne jest bezpieczne przechowywanie wartości klucza, aby zapobiec nieautoryzowanemu dostępowi i chronić integralność tokenów JWT.
Zdefiniuj kontroler API
Utwórz kontroler obsługujący punkty końcowe interfejsu API na potrzeby uwierzytelniania użytkowników.
autoryzacja użytkownika gniazda g kontrolera
Następnie skopiuj podany w this kod Plik repozytorium GitHubi dodaj go do user-auth.controller.ts plik — definiuje punkty końcowe do rejestracji użytkownika, logowania i pobierania danych użytkownika. The UseGuard (AuthGuard) decorator jest dołączony do wymuszania uwierzytelnienia dla pobierz użytkowników punktu końcowego, zapewniając dostęp tylko uwierzytelnionym użytkownikom.
Zaktualizuj plik user-auth.module.ts
Aby odzwierciedlić zmiany wprowadzone w projekcie, zaktualizuj plik user-auth.module.ts plik, aby skonfigurować niezbędne moduły, usługi i kontrolery do uwierzytelniania użytkowników.
import { Moduł, moduł zagnieżdżenia, użytkownik pośredniczący } z'@nestjs/wspólne';
import {JwtModuł} z'@nestjs/jwt';
import { UserAuthController} z'./user-auth.controller';
import {UsługaUwierzytelnianiaUżytkownika} z'./user-auth.service';
import {Moduł Mongoose} z'@nestjs/mangusta';
import { Schemat użytkownika } z„./schemas/user-auth.schema”;
import { sekretny klucz } z'./konfiguracja';@Moduł({
import: [
MongooseModule.forFeature([{nazwa: 'Użytkownik', schemat: UserSchema }]),
JwtModule.register({
sekret: tajnyKlucz.tajny,
signOptions: { wygasa w: „1h” },
}),
],
kontrolery: [UserAuthController],
dostawcy: [UserAuthService],
})
eksportklasa UserAuthModule przybory Moduł zagnieżdżenia {
skonfiguruj (konsument: MiddlewareConsumer) {
}
}
Na koniec uruchom serwer programistyczny i przetestuj punkty końcowe interfejsu API za pomocą programu Postman.
start biegu npm
Tworzenie bezpiecznych interfejsów API REST Nest.js
Tworzenie bezpiecznych interfejsów API REST Nest.js wymaga kompleksowego podejścia, które wykracza poza samo poleganie na JWT do uwierzytelniania i autoryzacji. Chociaż tokeny JWT są ważne, równie ważne jest wdrożenie dodatkowych środków bezpieczeństwa.
Dodatkowo, priorytetyzując bezpieczeństwo na każdym etapie rozwoju API, możesz zapewnić bezpieczeństwo swoich systemów zaplecza.