사용 이유
코드 jwt.strategy.ts (auth 폴더)
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { UserService } from '../user/user.service';
// jwt 전략은 guard에서 사용가능
@Injectable()
export class JwtAuthStrategy extends PassportStrategy(JwtStrategy) {
constructor(private usersService: UserService) {
super({
jwtFromRequest: ExtractJwt.fromExtractors([
(reuest) => reuest?.cookies?.accessToken, // 쿠키에서 추출
]),
secretOrKey: process.env.JWT_SECRET_KEY, // JWT 비밀키
});
}
async validate(payload: any) {
const user = await this.usersService.findUserId(payload._id);
// 필요한 정보만 리턴
return { _id: user._id, role: user.role }; // 필요한 최소 정보만 반환
}
}
코드 auth.module.ts (auth 폴더) - app.module.ts 및 사용하는 곳에 적요
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtAuthStrategy } from './jwt.strategy';
import { JwtAuthGuard } from './auth.guard';
import { UserService } from '../user/user.service';
import { UserModule } from 'src/user/user.module';
import { AdminModule } from 'src/admin/admin.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from 'src/user/entities/user.entity';
@Module({
imports: [
TypeOrmModule.forFeature([User]),
PassportModule,
UserModule,
AdminModule,
// jwt module 설정
JwtModule.registerAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
global: true,
secret: configService.get<string>('JWT_SECRET_KEY'),
signOptions: { expiresIn: '10m' },
}),
}),
],
providers: [JwtAuthStrategy, JwtAuthGuard, UserService],
exports: [JwtAuthGuard], // 다른 모듈에서 JwtAuthGuard를 사용할 수 있도록 export
})
export class AuthModule {}
코드 auth.guard.ts (auth 폴더)
import { Injectable, ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { AuthGuard as NestAuthGuard } from '@nestjs/passport';
import { Observable } from 'rxjs';
import { Request } from 'express';
@Injectable()
export class JwtAuthGuard extends NestAuthGuard('jwt') {
canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
const request: Request = context.switchToHttp().getRequest();
// 쿠키에서 JWT 토큰 추출
const token = request.cookies['accessToken']; // 쿠키에서 토큰 가져오기
if (token) {
// 토큰이 있을 경우, 요청에 JWT 토큰을 넣어서 인증 절차를 진행할 수 있게 만듦
request.headers['authorization'] = `Bearer ${token}`; // 헤더에도 토큰 심음, 나중에 한 번 해야함.
} else {
throw new UnauthorizedException('로그인을 진행해주세요.');
}
return super.canActivate(context); // Passport JWT 인증 전략을 실행
}
}
코드 admin.guard.ts (auth 폴더)
import { Injectable, ExecutionContext, ForbiddenException } from '@nestjs/common';
import { JwtAuthGuard } from './auth.guard'; // JwtAuthGuard 임포트
@Injectable()
export class AdminGuard extends JwtAuthGuard {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
// 요청에서 user 객체를 가져옵니다 (JwtAuthGuard에서 이미 설정됨)
const user = request.user;
// user가 없거나, role이 'admin'이 아니면 ForbiddenException 발생
if (!user || user.role !== 'admin') {
throw new ForbiddenException('관리자만 접근할 수 있습니다.');
}
return true;
}
}