NestJs JWT Login 적용기-1

김예찬·2022년 11월 23일
0

Passport

NestJs는 유저 인증을 위해

Passport 라이브러리를 사용할 것을 추천

Documentation | NestJS - A progressive Node.js framework

Local Strategy 적용

Passport 패키지 셋팅

$ npm install --save @nestjs/passport passport passport-local
$ npm install --save-dev @types/passport-local
  • 어떤 전략을 사용하든 @nestjs/passportpassport 패키지는 설치해야함
    • @nestjs/passportnestjs 에서 passport 전략 사용할 수 있게 해줌
  • passport-local은 유저이름/패스워드 인증 메커니즘
  • 앞에@types 붙은 패키지는 TypeScript code 쓸 때 도와주는 패키지

Passport-local

  • 유저이름/비밀번호 인증 매커니즘을 수행한다.
    • 유저 이름을 유저 이메일이나 아이디로 변경할 수 있다. (공식문서 HINT 참고)

auth/local.strategy.ts

  • 공식문서
    import { Strategy } from 'passport-local';
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { AuthService } from './auth.service';
    
    @Injectable()
    export class LocalStrategy extends PassportStrategy(Strategy) {
      constructor(private authService: AuthService) {
        super();
      }
    
      async validate(username: string, password: string): Promise<any> {
        const user = await this.authService.validateUser(username, password);
        if (!user) {
          throw new UnauthorizedException();
        }
        return user;
      }
    }
  • 내 코드
    import { Strategy } from 'passport-local';
    import { PassportStrategy } from '@nestjs/passport';
    import { Injectable, UnauthorizedException } from '@nestjs/common';
    import { AuthService } from './auth.service';
    
    @Injectable()
    export class LocalStrategy extends PassportStrategy(Strategy) {
      constructor(private authService: AuthService) {
        super({
    		 //유저이름을 이메일로 변경
          usernameField: 'email',
        });
      }
    
      async validate(email: string, password: string): Promise<any> {
        const user = await this.authService.validateUser(email, password);
        if (!user) {
          throw new UnauthorizedException();
        }
        return user;
      }
    }
  • authService의 validateUser 메소드로 유저 인증 세부 로직 구현
  • passport 전략이 바뀌면 validate 메소드의 parameter가 바뀐다.
  • 모든 전략에서 유저가 유효하다면 유저 정보를 반환하고 그렇지 않으면 인증에러를 반환한다.

AuthModule, AuthService 생성

$ nest g module auth
$ nest g service auth

auth/auth.service.ts

  • 공식문서
    import { Injectable } from '@nestjs/common';
    import { UsersService } from '../users/users.service';
    
    @Injectable()
    export class AuthService {
      constructor(private usersService: UsersService) {}
    
      async validateUser(username: string, pass: string): Promise<any> {
        const user = await this.usersService.findOne(username);
        if (user && user.password === pass) {
          const { password, ...result } = user;
          return result;
        }
        return null;
      }
    }
  • 내 코드
    import { Injectable } from '@nestjs/common';
    import { UserService } from 'src/user/user.service';
    import { JwtService } from '@nestjs/jwt';
    import * as bcrypt from 'bcrypt';
    
    @Injectable()
    export class AuthService {
      constructor(
        private userService: UserService,
      ) {}
    
      async validateUser(email: string, password: string): Promise<any> {
        //email을 parameter로 받기 때문에 email로 user정보 가져온다.
    		const user = await this.userService.findOneByEmail(email);
    		// user의 password는 bcrypt로 암호화 되었기 때문에 
    		// bcrypt의 compare 메소드로 클라이언드에서 보낸 password와 user의 password를 비교한다.
        const validatePassword = await bcrypt.compare(password, user.password);
        if (user && validatePassword) {
          const { password, ...result } = user;
          return result;
        }
        return null;
      }
    
    }

auth/auth.module.ts

  • 지금까지 정의한 Passport feature를 사용하기 위해 AuthModule을 이렇게 구성해야한다.
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';

@Module({
  imports: [UsersModule, PassportModule],
  providers: [AuthService, LocalStrategy],
})
export class AuthModule {}

Local Strategy 실행

Guard를 활용해 passport 전략을 실행한다.

→ 인증되지 않은 사용자의 접근을 차단한다.

Documentation | NestJS - A progressive Node.js framework

app.controller.ts

import { Controller, Request, Get, Post, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { AuthService } from './auth/auth.service';
import { LocalAuthGuard } from './auth/local-auth.guard';
@Controller()
export class AppController {
  constructor(private authService: AuthService) {}
// AuthGuard('local')을 상속하는 LocalAuthGuard 클래스
  @UseGuards(LocalAuthGuard)
  @Post('auth/login')
  async login(@Request() req) {
    return req.user;
  }
}
  • passport 전략을 통한 인증이 성공하면 반환되는 user 객체는 Request 객체에 req.user 형태로 할당된다.
profile
이 밤 등불의 친구

0개의 댓글