본문 바로가기
Node.js/nest.js

[NestJS / JWT / Passport] 로그인 1. LocalStrategy

by kiwi_wiki 2021. 4. 27.

이번에 로그인 기능을 구현해 볼 기회가 생겨서 작업한 것을 정리해보려 한다.

먼저 server 단에서 구현한 부분에 대해 작성할 것이다. 사실 client 측은 별게 없어서 안해도 될 거 같다.

(사용 스펙 : node.js, NestJS, JWT, passport, typeScript, typeORM)

 

전체적으로 구현한 것을 보면 jwt를 사용해 로그인 시 accessToken을 생성해 쿠키에 저장해 두고 로그인 상태를 관리할 수 있도록 구현했고, 로그인 상태에 따라 api 호출에 제한을 주기 위해 passport를 사용했다.

 

해당 기능을 개발하기 위해 추가한 라이브러리이다. 

npm install 명령어를 통해 추가하면 된다.

 

"@nestjs/jwt": "^7.2.0",
"@nestjs/passport": "^7.1.5",
"bcrypt": "^5.0.1",
"cookie-parser": "^1.4.5",
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",

먼저 로그인 api 호출시 유저가 정상적으로 로그인할 수 있는 상태인지 확인해주는 LocalStrategy를 구현한 것에 대해 정리해보려 한다.

 

/local.strategy.ts

import { PassportStrategy } from '@nestjs/passport';
import { AuthService } from '../services/auth.service';
import { Strategy } from 'passport-local';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { JwtPayload } from './jwt.payload';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super({
      usernameField: 'email',
      passwordField: 'password',
      passReqToCallback: false,
    });
  }

  async validate(email: string, password: string) {
    const payload: JwtPayload = { email, password };
    const user = await this.authService.validateAccount(payload);
    if (!user) {
      throw new HttpException('Invalid token', HttpStatus.UNAUTHORIZED);
    }
    return user;
  }
}

validate 메서드가 로그인 api 실행 이전에 먼저 실행되어 해당 유저의 상태를 검사해주는 역할을 해줄 것이다.

주의할 점은 기본적으로 username 과 password 필드로 설정이 되어있기 때문에 username 이 아닌 email 필드로 검사하고 싶다면 contructor에 위와 같이 usernameField: 'email' 을 설정해줘야 한다는 것이다.

 

LocalStrategy를 로그인 api 실행 이전에 먼저 실행되도록 하고 싶다면 로그인 api에 @UseGuards() 어노테이션을 추가해주면 된다.

 

/user.controller.ts

@UseGuards(AuthGuard('local'))
  @Post('/User/Login')
  public async login(@Body() dto: LoginUserDto, @Res() res: Response) {
    this.authService
      .login(dto)
      .then((result) => {
        res
          .status(HttpStatus.OK)
          .json(ResponseBody.createResponseBody().setBody(result));
      })
      .catch((e) => {
        console.log(e);
        res
          .status(HttpStatus.OK)
          .json(
            ResponseBody.createResponseBody()
              .setResultCode(RESULT_CODE.ERROR_BUT_IGNORED)
              .setErrorCode(ERROR_CODE.DB_DATA_NOT_FOUND)
              .setErrorDesc(e),
          );
      });
  }

 사용할 전략이 LocalStrategy 이기 때문에 @UseGuards(AuthGuard('local')) 을 추가해주면 /User/Login api 호출 시 AuthGuard 가 먼저 실행된다.

 

/user.dto.ts

export class LoginUserDto {
  email: string;
  password: string;
}

 

 

모듈을 추가해줌으로 사용 가능하게 해 준다.

 

/auth.module.ts

import { Module } from '@nestjs/common';
import { UserController } from '../controllers/user.controller';
import { AuthService } from '../services/auth.service';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from '../jwt/local.strategy';

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

 

/auth.service.ts

 

LocalStrategy에서 validate 메서드에서 실행되는 validateAccount의 내용이다.

async validateAccount(payload: JwtPayload) {
    const user: User = await this.userService.findByLogin(payload);
    if (user) {
      const { password, ...result } = user;
      return result;
    }
    return null;
  }

email과 password 정보로 db에서 유저를 찾고, 그 유저가 존재한다면 유저의 정보를 리턴하도록 구현했다.

(당연히 findByLogin()에 bcrypt로 암호화된 password와 파람으로 넘어온 password를 비교하여 검사하는 부분 존재)

 

다음 글 : [NestJS / JWT / Passport] 로그인 2. JWTStrategy
728x90
반응형

'Node.js > nest.js' 카테고리의 다른 글

[NestJS / JWT / Passport] 로그인 2. JWTStrategy  (2) 2021.04.28