NestJs - Authentication

choko's avatar
Jun 29, 2024
NestJs - Authentication
 
  • NestJS에서는 @nestjs/passport 모듈을 통해 authentication를 관리할 수 있다.
  • 설치
    • npm install --save @nestjs/passport passport passport-local
    • npm install --save-dev @types/passport-local
  • @nest/passport는 다음 단계들을 수행한다.
    • username/password, jwt의 token identity로 유저 인증
    • 유저 상태 관리(jwt)
    • 인증된 유저의 정보를 request에 붙여 router handler들에서 사용이 가능하게 한다.
    •  
       

Jwt 적용

  • jwt 발급 service
// auth.module.ts import { JwtModule } from '@nestjs/jwt'; @Module({ imports: [ UsersModule, JwtModule.register({ global: true, secret: jwtConstants.secret, signOptions: { expiresIn: '60s' }, }), ], providers: [AuthService], controllers: [AuthController], exports: [AuthService], }) export class AuthModule {} // auth.service.ts import { JwtService } from '@nestjs/jwt'; @Injectable() export class AuthService { constructor( private usersService: UsersService, private jwtService: JwtService ) {} async signIn(username: string, pass: string): Promise<{access_token: string}> { const user = await this.usersService.findOne(username); if (user?.password !== pass) { throw new UnauthorizedException(); } const payload = { sub: user.userId, username: user.username }; return { access_token: await this.jwtService.signAsync(payload), }; } } // response { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEsInVzZXJuYW1lIjoiam9obiIsImlhdCI6MTcwOTYyOTYxNiwiZXhwIjoxNzA5NjI5Njc2fQ.YuG_5Ic7fIIOjFLfucpyTidHUUobHkiGYIfotYWwB_A" }
 
  • Authentication guard 구현
    • auth.guard.ts
      • import { CanActivate, ExecutionContext, Injectable, UnauthorizedException, } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { jwtConstants } from './constants'; import { Request } from 'express'; @Injectable() export class AuthGuard implements CanActivate { // -> guard constructor(private jwtService: JwtService) {} async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest(); const token = this.extractTokenFromHeader(request); if (!token) { throw new UnauthorizedException(); } try { const payload = await this.jwtService.verifyAsync( token, { secret: jwtConstants.secret } ); // 💡 We're assigning the payload to the request object here // so that we can access it in our route handlers request['user'] = payload; // -> 조회 시 @Req() request; request.user.username으로 조회 } catch { throw new UnauthorizedException(); } return true; } private extractTokenFromHeader(request: Request): string | undefined { const [type, token] = request.headers.authorization?.split(' ') ?? []; return type === 'Bearer' ? token : undefined; } }
    • auth.controller.ts
      • @Controller('auth') export class AuthController { constructor(private authService: AuthService) {} @HttpCode(HttpStatus.OK) @Post('login') signIn(@Body() signInDto: Record<string, any>) { return this.authService.signIn(signInDto.username, signInDto.password); } @UseGuards(AuthGuard) @Get('profile') getProfile(@Request() req) { return req.user; } }
      • login으로 jwt 토큰을 받고, http header의 bearer 토큰에 넣어 보내주면, getProfile에 접근할 수 있다.
 
 

Enable authentication globally

  • Jwt 필터를 global하게 설정하고, @Public() 데코레이터가 붙은 컨트롤러는 jwt 인증을 거치지 않게 해보자.
    • global
      • providers: [ { provide: APP_GUARD, useClass: AuthGuard, }, ],
    • setMetadata로 custom decorator 선언
      • import { SetMetadata } from '@nestjs/common'; export const IS_PUBLIC_KEY = 'isPublic'; export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
      • 이러면 다음과 같이 데코레이터를 사용할 수 있다.
        • @Public() @Get() findAll() { return []; }
         
    • AuthGuard를 isPublic 데코레이터는 항상 true를 반환하도록 바꿔준다.
    • @Injectable() export class AuthGuard implements CanActivate { constructor(private jwtService: JwtService, private reflector: Reflector) {} async canActivate(context: ExecutionContext): Promise<boolean> { const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) { // 💡 See this condition return true; } // ... 이하 동일 // }
Share article

Tom의 TIL 정리방