Използвайте структурираната архитектура на Nest, за да изградите сигурни и ефективни REST API.

Express.js е страхотна технология за изграждане на сигурни и стабилни REST API, но не предоставя предварително дефинирана структура. Минималистичният му характер ви позволява да управлявате основни аспекти като маршрутизиране, организация на кода и мерки за сигурност ръчно или чрез използване на наличния междинен софтуер и библиотеки.

За разлика от това, Nest.js, изграден върху Express.js и Node.js, въвежда абстракция от по-високо ниво който предлага ясна структура, стабилен подход за организация на кода и опростена реализация подробности. По същество Nest.js предоставя по-структурирана архитектура за изграждане на ефективни и сигурни backend API и услуги.

Настройване на проект Nest.js

За да започнете, първо трябва да инсталирате командния ред (CLI) на Nest.js глобално, като изпълните командата по-долу:

npm i -g @nestjs/cli

След като инсталацията приключи, продължете напред и създайте нов проект, като изпълните:

instagram viewer
гнездо нов nest-jwt-api

След това Nest.js CLI ще ви подкани да изберете мениджър на пакети за инсталиране на зависимостите. За този урок ще използваме npm, мениджърът на пакети на възли. Изберете npm и изчакайте, докато CLI създаде основен проект Nest.js и инсталира всички необходими конфигурационни файлове и първоначални зависимости, необходими за стартиране на приложението.

След като проектът е настроен, отидете до директорията на проекта и стартирайте сървъра за разработка.

cd nest-jwt-api
npm изпълнение стартиране

Накрая изпълнете командата по-долу, за да инсталирате пакетите, които ще използваме за този проект.

npm инсталирайте mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt

Можете да намерите кода на този проект тук GitHub хранилище.

Конфигуриране на MongoDB връзка с база данни

Настройте база данни MongoDB локално или конфигурирайте MongoDB клъстер в облака. След като настроите базата данни, копирайте URI низа за връзка с базата данни, създайте a .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 модул потребителско удостоверяване

CLI инструментът Nest.js автоматично генерира необходимите модулни файлове. Освен това ще актуализира app.module.ts файл, включващ необходимите промени, свързани с модула за удостоверяване на потребителя.

Можете да изберете да създадете основните конфигурационни файлове на проекта ръчно, въпреки това CLI инструментът опростява този процес чрез автоматично създаване на необходимите елементи, в допълнение към съответното актуализиране на промените в на app.module.ts файл.

Създайте потребителска схема

Вътре в новосъздаденото потребителско удостоверяване папка в src директория, създайте нова schemas/user-auth.schema.ts файл и добавете следния код, за да създадете схема на Mongoose за Потребител модел

импортиране { Prop, Schema, SchemaFactory } от„@nestjs/mongoose“;
импортиране {Документ} от"мангуста";

@Схема({ клеймото за време: вярно })
износклас потребител {
@Prop()
потребителско име: низ;
@Prop()
парола: низ;
}

износТип UserDocument = Потребител & Документ;
износконст UserSchema = SchemaFactory.createForClass (Потребител);

Създаване на услугата за удостоверяване на потребителя

Сега нека създадем услугата за удостоверяване на потребителя, която ще управлява логиката за удостоверяване за REST API, като изпълни командата по-долу:

nest g услуга потребителско удостоверяване

Тази команда ще създаде a потребител-auth.service.ts файл в директорията за удостоверяване на потребителя. Отворете този файл и го актуализирайте със следния код.

  1. Първо, направете следните импорти.
    импортиране { Injectable, NotFoundException, Logger, UnauthorizedException } от„@nestjs/common“;
    импортиране { InjectModel } от„@nestjs/mongoose“;
    импортиране { Модел } от"мангуста";
    импортиране { потребител } от'./schemas/user-auth.schema';
    импортиране * като bcrypt от'bcrypt';
    импортиране {JwtService} от„@nestjs/jwt“;
  2. След това създайте a UserAuthService клас, който капсулира функционалността за регистрация на потребител, влизане и извличане на всички маршрути на потребителски данни.
@Инжекционен()
износклас UserAuthService {
частен регистратор само за четене = нов Логер (UserAuthService.name);
конструктор(@InjectModel(потребителско.име) частен userModel: Модел, частен jwtService: JwtService) {}

асинхронен registerUser (потребителско име: низ, парола: низ): обещаниениз }> {
опитвам {
конст хеш = изчакайте bcrypt.hash (парола, 10);
изчакайтетова.userModel.create({ потребителско име, парола: хеш});
връщане { съобщение: „Потребителят се регистрира успешно“ };
} улов (грешка) {
хвърлямновГрешка(„Възникна грешка при регистриране на потребителя“);
}
 }

асинхронен loginUser (потребителско име: низ, парола: низ): обещание<низ> {
опитвам {
конст потребител = изчакайтетова.userModel.findOne({потребителско име});
ако (!потребител) {
хвърлямнов NotFoundException(„Потребителят не е намерен“);
}
конст PasswordMatch = изчакайте bcrypt.compare (парола, потребителска.парола);
ако (!passwordMatch) {
хвърлямнов UnauthorizedException(„Невалидни идентификационни данни за вход“);
}
конст полезен товар = {userId: user._id};
конст жетон = това.jwtService.sign (полезен товар);
връщане жетон;
} улов (грешка) {
конзола.log (грешка);
хвърлямнов UnauthorizedException(„Възникна грешка при влизане“);
}
}

асинхронен getUsers(): обещание {
опитвам {
конст потребители = изчакайтетова.userModel.find({});
връщане потребители;
} улов (грешка) {
това.logger.error(`Възникна грешка при извличане на потребители: ${error.message}`);
хвърлямновГрешка(„Възникна грешка при извличане на потребители“);
}
}
}

The UserAuthService клас прилага логиката на потребителска регистрация, влизане и извличане на потребителски данни. Той използва userModel за взаимодействие с базата данни и извършване на необходимите действия, включително хеширане на паролата по време на регистрация, валидиране на идентификационни данни за вход и накрая, генериране на JWT токени след успех удостоверяване.

Внедряване на Authentication Guard

За да се гарантира сигурността на чувствителните ресурси, е изключително важно да се ограничи достъпът изключително до оторизирани потребители. Това се постига чрез налагане на мярка за сигурност, която изисква наличието на валиден JWT в последващи API заявки, направени към защитени крайни точки, в този случай, потребители маршрут. В потребителско удостоверяване директория, създайте нова auth.guard.ts файл и добавете кода по-долу.

импортиране { CanActivate, ExecutionContext, Injectable, UnauthorizedException } от„@nestjs/common“;
импортиране {JwtService} от„@nestjs/jwt“;
импортиране { Заявка } от"експресен";
импортиране { секретен ключ } от'./config';

@Инжекционен()
износклас AuthGuard инструменти CanActivate {
конструктор(частен jwtService: JwtService) {}

асинхронен canActivate (контекст: ExecutionContext): обещание<булево> {
конст заявка = context.switchToHttp().getRequest();
конст жетон = това.extractTokenFromHeader (заявка);
ако (!токен) {
хвърлямнов UnauthorizedException();
}
опитвам {
конст полезен товар = изчакайтетова.jwtService.verifyAsync (токен, {
тайна: secretKey.secret,
});
заявка ["потребител"] = полезен товар;
} улов {
хвърлямнов UnauthorizedException();
}
връщаневярно;
}
частен extractTokenFromHeader (заявка: Заявка): низ | недефиниран {
конст [Тип, токен] = request.headers.authorization?.split(' ')?? [];
връщанеТип"носител"? токен: недефиниран;
}
}

Кодът имплементира a пазач, както е посочено в официалната документация, за защита на маршрутите и гарантиране, че само удостоверени потребители с валиден JWT токен имат достъп до тях.

Той извлича JWT токена от заглавката на заявката, проверява неговата автентичност с помощта на JwtService, и присвоява декодирания полезен товар на заявка['потребител'] имущество за по-нататъшна обработка. Ако токенът липсва или е невалиден, той хвърля an UnauthorizedException за предотвратяване на достъпа до защитения маршрут.

Сега създайте config.ts файл в същата директория и добавете кода по-долу.

износконст secretKey = {
тайна: „ТАЙНА СТОЙНОСТ.“,
};

Този таен ключ се използва за подписване и проверка на автентичността на JWT. Важно е стойността на ключа да се съхранява сигурно, за да се предотврати неоторизиран достъп и да се защити целостта на JWT.

Дефинирайте API контролера

Създайте контролер, който управлява крайните точки на API за удостоверяване на потребителя.

nest g контролер user-auth

След това копирайте кода, предоставен в това Файл хранилище GitHubи го добавете към потребител-auth.controller.ts файл—той дефинира крайните точки за потребителска регистрация, влизане и извличане на потребителски данни. The UseGuards (AuthGuard) е включен декоратор за налагане на удостоверяване за getUsers крайна точка, като се гарантира, че само удостоверени потребители имат достъп.

Актуализирайте файла user-auth.module.ts

За да отразите промените, направени в проекта, актуализирайте потребител-auth.module.ts файл за конфигуриране на необходимите модули, услуги и контролери за удостоверяване на потребителя.

импортиране { Модул, NestModule, MiddlewareConsumer } от„@nestjs/common“;
импортиране {JwtModule} от„@nestjs/jwt“;
импортиране { UserAuthController } от'./user-auth.controller';
импортиране {UserAuthService} от'./user-auth.service';
импортиране { MongooseModule } от„@nestjs/mongoose“;
импортиране { UserSchema } от'./schemas/user-auth.schema';
импортиране { секретен ключ } от'./config';

@Модул({
внос: [
MongooseModule.forFeature([{ име: "Потребител", схема: UserSchema }]),
JwtModule.register({
тайна: secretKey.secret,
signOptions: { expiresIn: „1ч“ },
}),
],
контролери: [UserAuthController],
доставчици: [UserAuthService],
})

износклас UserAuthModule инструменти NestModule {
конфигуриране (потребител: MiddlewareConsumer) {
}
}

И накрая, завъртете сървъра за разработка и тествайте крайните точки на API с помощта на Postman.

npm изпълнение стартиране

Изграждане на Secure Nest.js REST API

Изграждането на сигурни Nest.js REST API изисква цялостен подход, който надхвърля просто разчитането на JWT за удостоверяване и оторизация. Докато JWT са важни, също толкова важно е да се приложат допълнителни мерки за сигурност.

Освен това, като приоритизирате сигурността на всеки етап от разработката на API, можете да гарантирате сигурността на вашите бекенд системи.