• Home
  • About
    • lahuman photo

      lahuman

      열심히 사는 아저씨

    • Learn More
    • Facebook
    • LinkedIn
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

nestjs에서 guard에 Global service Inject 처리

08 Aug 2023

Reading time ~2 minutes

nestjs에서 guard에 Global service Inject 처리

guard에서 특정 Module의 서비스를 사용하고 있는 상화에서 해당 guard를 다른 Module에서 사용하려면 사용하려는 Module에서 해당 Service를 import 해야 합니다. 이를 Global 처리를 이용한 전략 스토어를 사용하는 예제 입니다.

Global Map 생성 및 전략 등록

// Global로 사용될 Map 생성
// https://github.com/lahuman/daily-quest/blob/main/api/src/auth/strategy-storage.ts
export const StrategyStorage = new Map();

// https://github.com/lahuman/daily-quest/blob/main/api/src/auth/auth.strategy.ts
import { Injectable } from '@nestjs/common';
import { UserService } from '../user/users.service';
import { StrategyStorage } from './strategy-storage';
import { UserTokenVo } from '../user/user-token.vo';
import { FirebaseService } from '../firebase/firebase.service';
import { UserVO } from '..//user/user.vo';

@Injectable()
export class AuthStrategy {
  constructor(
    private userService: UserService,
    private firebaseService: FirebaseService,
  ) {
    // 초기 기동시 Global로 사용될 Map에 AuthStrategy.name로 해당 클래스 인스턴스 저장
    StrategyStorage.set(AuthStrategy.name, this);
  }

  // 필요한 method 생성
  fbVerify(token: string) {
    return this.firebaseService.authTokenVerify(token);
  }
  userVerify(token: string): UserVO {
    return this.userService.tokenValidate(token);
  }
}

전략을 초기화 할 수 있도록 app.module에 선언

// https://github.com/lahuman/daily-quest/blob/main/api/src/app.module.ts
import { Logger, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { UsersModule } from './user/user.module';
import { FirebaseModule } from './firebase/firebase.module';
import { ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SnakeNamingStrategy } from './core/snake-naming.strategy';
import { join } from 'path';
import { TodoModule } from './todo/todo.module';
import { AuthStrategy } from './auth/auth.strategy';
import { AllExceptionsFilter } from './core/exception.filter';
import { APP_FILTER } from '@nestjs/core';

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('./core/snake-naming.strategy').SnakeNamingStrategy;

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: ['.env.local', '.env'],
      isGlobal: true,
    }),
    TypeOrmModule.forRoot({
      type: 'sqlite',
      namingStrategy: new SnakeNamingStrategy(),
      database: process.env.DB_SCHEMA,
      enableWAL: true,
      synchronize: false,
      entities: [join(__dirname, '**/*.entity.{ts,js}')],
      subscribers: [],
      logging: true,
      maxQueryExecutionTime: 1000, // 1초 이상되는 모든 쿼리 등록
      extra: {
        synchronous: 'normal',
        temp_store: 'memory',
        mmap_size: 30000000000,
        page_size: 32768,
      },
    }),
    UsersModule,
    TodoModule,
    FirebaseModule,
  ],
  controllers: [AppController],
  providers: [
    AuthStrategy, // 제공할 AuthStrategy providers 처리 
    {
      // ExceptionFilter 등록
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
    },
  ],
})
export class AppModule {}

guard 사용 예제

// https://github.com/lahuman/daily-quest/blob/main/api/src/user/user.guard.ts
import {
  CanActivate,
  ExecutionContext,
  HttpException,
  HttpStatus,
  Injectable,
  Logger,
} from '@nestjs/common';
import { StrategyStorage } from '../auth/strategy-storage';
import { AuthStrategy } from '../auth/auth.strategy';

@Injectable()
export class UserGuard implements CanActivate {
  logger: Logger = new Logger(UserGuard.name);

  async canActivate(context: ExecutionContext) {
    const req = context.switchToHttp().getRequest();
    const token = req.headers.authorization
      ? req.headers.authorization.split('Bearer ')[1]
      : '';

    if (token === '' || token === undefined) {
      throw new HttpException(
        { status: HttpStatus.UNAUTHORIZED, error: 'Token Is Not Found.' },
        HttpStatus.UNAUTHORIZED,
      );
    }

    req.user = await StrategyStorage.get(AuthStrategy.name).userVerify(token); // 필요한 AuthStrategy.name의 서비스에서 호출 및 사용
    const user = req.user;
    if (!user) {
      return false;
    }

    this.logger.debug('UserGuard ok ::');
    return true;
  }
}

Inject service into guard in Nest.JS를 보면 nestjs/passport 에서 영감을 얻은 내용이라고 합니다.

참고 자료

  • Inject service into guard in Nest.JS


nestjsguardservice Share Tweet +1