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 에서 영감을 얻은 내용이라고 합니다.