На этом уроке мы узнаем, как реализовать аутентификацию и авторизацию в приложении NestJS с использованием Passport и JWT.

  • Установите необходимые пакеты: Установите необходимые пакеты для Passport, JWT и хеширования паролей:
npm install --save @nestjs/passport @nestjs/jwt passport passport-jwt bcryptjs
  • Создайте сущность пользователя: создайте новый файл с именем user.entity.ts в папке src и добавьте следующий код:
import { Entity, PrimaryGeneratedColumn, Column, Unique } from 'typeorm';

@Entity()
@Unique(['username'])
export class User {
  @PrimaryGeneratedColumn()
  id: number;
  @Column()
  username: string;
  @Column()
  password: string;
}
  • Создайте UserService: создайте новый файл с именем user.service.ts внутри папки src и добавьте следующий код:
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import * as bcrypt from 'bcryptjs';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}
  async createUser(username: string, password: string): Promise<User> {
    const hashedPassword = await bcrypt.hash(password, 10);
    const newUser = this.userRepository.create({
      username,
      password: hashedPassword,
    });
    return this.userRepository.save(newUser);
  }
}
  • Создайте AuthModule: создайте новый файл с именем auth.module.ts внутри папки src и добавьте следующий код:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserService } from './user.service';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UserService],
})
export class AuthModule {}
  • Обновите AppModule: импортируйте AuthModule в файл app.module.ts:
import { AuthModule } from './auth.module';

@Module({
  imports: [
    AuthModule,
    // ...
  ],
  providers: [AppResolver, AppService],
})
export class AppModule {}
  • Создайте JwtStrategy: создайте новый файл с именем jwt.strategy.ts внутри папки src и добавьте следующий код:
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UserService } from './user.service';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private userService: UserService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: '<your_jwt_secret>',
    });
  }
  async validate(payload: any) {
    const user = await this.userService.findOne(payload.username);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

Обязательно замените <your_jwt_secret> своим собственным секретом JWT.

  • Создайте AuthService: создайте новый файл с именем auth.service.ts в папке src и добавьте следующий код:
import { Injectable } from '@nestjs/common';
import { UserService } from './user.service';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcryptjs';

@Injectable()
export class AuthService
{ 
constructor( private userService: UserService, private jwtService: JwtService, ) {}

async validateUser(username: string, password: string): Promise<any> {
 const user = await this.userService.findOne(username);
 if (user && (await bcrypt.compare(password, user.password))) {
   return user; 
  } 
  return null; 
}

async login(user: any) {
   const payload = {
     username: user.username, sub: user.userId 
    };
   return { access_token: this.jwtService.sign(payload), };
 }
}
  • Обновите AuthModule: обновите файл auth.module.ts, включив в него новый AuthService и JwtStrategy:
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { UserService } from './user.service';
import { AuthService } from './auth.service';
import { JwtStrategy } from './jwt.strategy';
import { User } from './user.entity';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forFeature([User]),
    PassportModule,
    JwtModule.register({
      secret: '<your_jwt_secret>',
      signOptions: { expiresIn: '1h' },
    }),
  ],
  providers: [UserService, AuthService, JwtStrategy],
})
export class AuthModule {}

Обязательно замените <your_jwt_secret> своим собственным секретом JWT.

  • Защита маршрутов GraphQL: обновите файл app.module.ts, включив в него конфигурацию GraphQLModule.forRoot(), и используйте параметр context, чтобы добавить пользователя в контекст GraphQL:
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { AuthModule } from './auth.module';
// ...

@Module({
  imports: [
    AuthModule,
    // ...
    GraphQLModule.forRoot({
      autoSchemaFile: 'schema.gql',
      context: ({ req }) => ({ user: req.user }),
    }),
  ],
  // ...
})
export class AppModule {}
  • AuthGuard: теперь вы можете защитить любой преобразователь GraphQL с помощью декоратора @UseGuards():
import { UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Query('protectedData')
@UseGuards(AuthGuard('jwt'))
async getProtectedData(@Context('user') user: User) {
  // Your protected data logic here
}

Теперь вы реализовали аутентификацию и авторизацию с помощью Passport и JWT в своем приложении NestJS. Вы можете использовать это как отправную точку для дальнейшей настройки и расширения функций безопасности вашего приложения.