текст перекладу
Фото від Timothy Cuenat на Unsplash
Аутентифікація є критично важливою частиною будь-якого застосунку, але вона не обов'язково має бути складною. У цій статті я проведу вас через процес створення простого, але надійного механізму аутентифікації користувачів за допомогою NestJS та Prisma. Prisma спрощує управління базами даних, виступаючи як інструмент ORM (Object-Relational Mapping), дозволяючи нам визначати та взаємодіяти з нашою схемою бази даних без зайвих зусиль. Ми розглянемо все, починаючи від налаштування схеми бази даних до впровадження JWT для захисту маршрутів — все в ефективному та зручному для початківців форматі.
Передумови
- Встановлений Node.js
- Базові знання Typescript та NestJS
Встановлення NestJS CLI глобально
Запустіть цей код у вашому терміналі для встановлення NestJS CLI на вашу систему
npm install -g @nestjs/cli
Створення нового проекту NestJS
Ця команда створює новий проект NestJS під назвою ‘auth-demo’.
nest new auth-demo
Встановлення залежностей
Перейдіть у директорію проекту, а потім встановіть залежності, які ми будемо використовувати. Остання частина коду встановлює prisma як залежність для розробки, оскільки вона не потрібна у виробництві.
prisma
: інструмент для взаємодії з базами даних у типізованому вигляді.@prisma/client
: бібліотека-клієнт, створена Prisma для взаємодії з вашою базою даних.bcryptjs
: бібліотека для хешування та перевірки паролів.jsonwebtoken
: бібліотека для створення та перевірки JSON Web Tokens (JWT), які використовуються для аутентифікації.@nestjs/config
: бібліотека nestjs, яку ми будемо використовувати для налаштування та роботи з нашими змінними середовища.
cd auth-demo
npm install prisma @prisma/client bcryptjs jsonwebtoken @nestjs/config
npm install -D prisma
Ініціалізація Prisma
Це ініціалізує prisma у вашому проекті та створить папку prisma, яка містить ваш файл схеми.
npx prisma init
Оновлення змінних середовища
Файл prisma/schema.prisma
вже очікує змінну середовища з назвою ‘DATABASE_URL’ з вашого файлу .env
. Ваш файл .env має виглядати приблизно так. Замініть рядок на ваш фактичний рядок підключення до бази даних.
Створення та міграція схеми User
Додайте наступний код в кінець файлу prisma/schema.prisma
для створення схеми для користувача
model User {
id Int @id @default(autoincrement())
email String @unique
password String
createdAt DateTime @default(now())
}
Після збереження цього файлу, запустіть наступний код, щоб виконати міграцію схеми користувача в вашу базу даних. Це створить таблицю під назвою ‘User’ у вашій базі даних з відповідними атрибутами та типами даних.
npx prisma migrate dev --name init
Генерація Prisma модуля та сервісу
CLI NestJS дозволяє нам запускати деякі команди для генерації необхідних файлів безпосередньо з терміналу. Ми будемо використовувати це для створення модуля та сервісу для prisma. Це створить папку з назвою ‘prisma’ з необхідними файлами.
nest generate module prisma
nest generate service prisma
Ваш файл src/prisma/prisma.module.ts
має виглядати ось так:
import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
Ваш файл src/prisma/prisma.service.ts
має виглядати ось так.
текст перекладу
Це налаштує базу даних на URL, вказаний у вашому файлі .env
.
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient {
constructor(private configService: ConfigService) {
super({
datasources: {
db: {
url: configService.get('DATABASE_URL'),
},
},
});
}
}
Генерація модуля, контролера та сервісу для аутентифікації
Використовуючи CLI NestJS, ми створимо модуль аутентифікації, контролер та сервіс за допомогою наступних команд.
nest generate module auth
nest generate service auth
nest generate controller auth
Ваш файл src/auth/auth.module.ts
має виглядати так:
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { PrismaService } from 'src/prisma/prisma.service';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [ConfigModule],
providers: [AuthService, PrismaService],
exports: [AuthService],
})
export class AuthModule {}
Ми будемо створювати сервіс аутентифікації з функціями для хешування та соління паролів за допомогою bcrypt, генерації та перевірки токенів за допомогою Json Web Tokens та, зрештою, для входу та реєстрації. Ваш файл src/auth/auth.service.ts
має виглядати так:
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import * as bcrypt from 'bcrypt';
import * as jwt from 'jsonwebtoken';
@Injectable()
export class AuthService {
private readonly jwtSecret = 'supersecretkey'; // Замініть на .env для безпеки
constructor(private prisma: PrismaService) {}
async hashPassword(password: string): Promise {
const salt = await bcrypt.genSalt();
return bcrypt.hash(password, salt);
}
async generateToken(userId: number): Promise {
return jwt.sign({ userId }, this.jwtSecret, { expiresIn: '1h' });
}
async register(email: string, password: string): Promise<{ token: string }> {
const hashedPassword = await this.hashPassword(password);
const user = await this.prisma.user.create({
data: { email, password: hashedPassword },
});
const token = await this.generateToken(user.id);
return { token };
}
async login(email: string, password: string): Promise<{ token: string }> {
const user = await this.prisma.user.findUnique({ where: { email } });
if (!user || !(await bcrypt.compare(password, user.password))) {
throw new UnauthorizedException('Невірні дані для входу');
}
const token = await this.generateToken(user.id);
return { token };
}
async validateToken(token: string): Promise {
try {
return jwt.verify(token, this.jwtSecret);
} catch (error) {
throw new UnauthorizedException('Невірний або прострочений токен');
}
}
}
Наступним кроком ми налаштуємо контролер для обробки запитів на вхід та вихід. Ваш файл src/auth/auth.controller.ts
має виглядати так.
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
// Це буде отримувати запити на '/auth/register'
@Post('register')
async register(@Body() body: { email: string; password: string }) {
return this.authService.register(body.email, body.password);
}
// Це буде отримувати запити на '/auth/login'
@Post('login')
async login(@Body() body: { email: string; password: string }) {
return this.authService.login(body.email, body.password);
}
}
Налаштування проміжного програмного забезпечення для перевірки токенів
Для покращення безпеки ми впроваджуємо Json Web Tokens для перевірки користувачів. Для цього ми налаштуємо проміжне програмне забезпечення.
текст перекладу
У контексті NestJS, проміжне програмне забезпечення (middleware) можна розглядати як функцію, яка виконується до обробників маршруту.
Спочатку ми створимо проміжне програмне забезпечення, виконавши:
nest generate middleware auth
Це створить файл src/auth/auth.middleware.ts
. У цьому файлі ми налаштуємо проміжне програмне забезпечення для перевірки вхідних запитів, перевіряючи наявність дійсного заголовка Authorization
, що містить JSON Web Token (JWT). Проміжне програмне забезпечення перехоплює кожен запит, перевіряє токен за допомогою AuthService
і додає декодовану інформацію про користувача до об'єкта запиту для подальшого використання в контролерах. Якщо токен відсутній, недійсний або прострочений, проміжне програмне забезпечення зупиняє запит і повертає помилку UnauthorizedException
. Ваш файл src/auth/auth.middleware.ts
має виглядати так:
import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';
import { Request, Response, NextFunction } from 'express';
@Injectable()
export class AuthMiddleware implements NestMiddleware {
constructor(private authService: AuthService) {}
async use(req: Request, res: Response, next: NextFunction) {
const authHeader = req.headers['authorization'];
if (!authHeader) {
throw new UnauthorizedException('Authorization header is missing');
}
const token = authHeader.split(' ')[1];
if (!token) {
throw new UnauthorizedException('Token is missing');
}
try {
const payload = await this.authService.validateToken(token);
req['user'] = payload;
next();
} catch (error) {
throw new UnauthorizedException('Invalid or expired token');
}
}
}
Застосування проміжного програмного забезпечення
Щоб застосувати проміжне програмне забезпечення для аутентифікації в нашому застосунку, нам потрібно оновити файл src/app.module.ts
, щоб він виглядав так:
import { MiddlewareConsumer, Module } from '@nestjs/common';
import { AuthMiddleware } from './auth/auth.middleware';
import { AuthModule } from './auth/auth.module';
import { PrismaModule } from './prisma/prisma.module';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
AuthModule,
PrismaModule,
],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(AuthMiddleware).forRoutes('*');
}
}
Отже, це в принципі все! Я розумію, що це досить детально, але я хотів переконатися, що кожен крок зрозумілий, щоб ви могли легко йти слідом. Ви можете взяти цей код, налаштувати його за потребою і використовувати у своїх проектах. Дякую за вашу увагу, не забувайте поставити аплауз і поділитися. Сподіваюся, що це було корисно. Бажаю чудового дня і до зустрічі в наступному матеріалі! Па-па!
Перекладено з: Effortless User Authentication with NestJS and Prisma: A Beginner-Friendly Guide