Реализация JWT авторизации с ролями в NestJS с использованием Prisma
В этом примере мы создадим систему авторизации с использованием JWT в NestJS, где роли (student
и teacher
) будут определять доступ к API. Мы будем использовать Prisma для работы с базой данных.
Шаг 1: Установка необходимых пакетов
Установите зависимости для работы с JWT:
bash
npm install @nestjs/jwt @nestjs/passport passport passport-jwt bcrypt @prisma/client
npm install -D @types/passport-jwt
Шаг 2: Настройка Prisma модели
Добавьте модель пользователей с ролями в файл prisma/schema.prisma
:
prisma
model User {
id Int @id @default(autoincrement())
email String @unique
password String
role Role
}
enum Role {
STUDENT
TEACHER
}
После этого выполните миграцию:
bash
npx prisma migrate dev --name add_user_roles
Шаг 3: Создание модуля аутентификации
- Создайте модуль
auth
:bashnest generate module auth nest generate service auth nest generate controller auth
- Настройте
auth.service.ts
для обработки JWT и проверки пользователей:typescriptimport { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import * as bcrypt from 'bcrypt'; import { PrismaService } from '../prisma/prisma.service'; @Injectable() export class AuthService { constructor(private jwtService: JwtService, private prisma: PrismaService) {} async validateUser(email: string, password: string) { const user = await this.prisma.user.findUnique({ where: { email } }); if (user && (await bcrypt.compare(password, user.password))) { const { password, ...result } = user; return result; } return null; } async login(user: any) { const payload = { email: user.email, sub: user.id, role: user.role }; return { access_token: this.jwtService.sign(payload), }; } }
- Настройте
auth.controller.ts
для маршрутов аутентификации:typescriptimport { Controller, Post, Body, Request, UseGuards } from '@nestjs/common'; import { AuthService } from './auth.service'; import { LocalAuthGuard } from './guards/local-auth.guard'; @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} @Post('login') @UseGuards(LocalAuthGuard) async login(@Request() req) { return this.authService.login(req.user); } }
- Настройте стратегию
local
для проверки логина:typescriptimport { Strategy } from 'passport-local'; import { PassportStrategy } from '@nestjs/passport'; import { Injectable, UnauthorizedException } from '@nestjs/common'; import { AuthService } from '../auth.service'; @Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService) { super({ usernameField: 'email' }); } async validate(email: string, password: string): Promise<any> { const user = await this.authService.validateUser(email, password); if (!user) { throw new UnauthorizedException(); } return user; } }
- Настройте стратегию
jwt
для защиты маршрутов:typescriptimport { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'your_jwt_secret', }); } async validate(payload: any) { return { userId: payload.sub, email: payload.email, role: payload.role }; } }
Шаг 4: Реализация ролей
- Создайте
roles.guard.ts
для проверки ролей:typescriptimport { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler()); if (!requiredRoles) { return true; } const { user } = context.switchToHttp().getRequest(); return requiredRoles.includes(user.role); } }
- Создайте декоратор
roles.decorator.ts
:typescriptimport { SetMetadata } from '@nestjs/common'; export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
Шаг 5: Пример использования ролей в контроллере
- Создайте контроллер для работы с оценками:bash
nest generate controller grades
- Настройте маршруты в
grades.controller.ts
:typescriptimport { Controller, Get, Post, Body, UseGuards } from '@nestjs/common'; import { Roles } from '../auth/roles.decorator'; import { RolesGuard } from '../auth/guards/roles.guard'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; @Controller('grades') export class GradesController { @Get() @UseGuards(JwtAuthGuard, RolesGuard) @Roles('STUDENT', 'TEACHER') getGrades() { return 'Просмотр оценок'; } @Post() @UseGuards(JwtAuthGuard, RolesGuard) @Roles('TEACHER') setGrade(@Body() body: { studentId: number; grade: number }) { return `Оценка ${body.grade} поставлена студенту ${body.studentId}`; } }
Шаг 6: Тестирование
- Зарегистрируйте пользователей с ролями
STUDENT
иTEACHER
в базе данных. - Выполните вход через
/auth/login
, чтобы получить JWT токен. - Используйте токен для доступа к маршрутам:
- GET /grades: Доступен для
STUDENT
иTEACHER
. - POST /grades: Доступен только для
TEACHER
.
- GET /grades: Доступен для
Теперь у вас есть система авторизации с JWT и ролями в NestJS, интегрированная с Prisma!