본문 바로가기

Learning/NestJS

NestJS Authentication(1) Login

니콜라스 NestJS 강좌를 듣고 토이프로젝트의 백엔드를 NestJS로 선택

CLUD 코딩 중 인증부분이 필요하여 공식 문서를 찾아 구현

 

NestJS 공식 문서에서 Authentication 부분을 크롬에서 번역하여 공부를 시작

 

NestJS 깃에 sample에 인증 관련이 있어 같이 열어 놓고 공부

 

공식문서에는 node.js의 인증 라이브러리인 passport와 사용자 자격증명에 JSON 웹토큰(jwt)를 사용하는것 같다.

인증상태 관리는 jwt혹은 express session 을 사용한다 라고 되어 있음.

 

$ npm install --save @nestjs/passport passport passport-local
$ npm install --save-dev @types/passport-local

$ npm install --save @nestjs/jwt passport-jwt
$ npm install --save-dev @types/passport-jwt

우선 필요한 패키지를 설치 한다.

공식문서에는 jwt를 따로 설명해 놨는데 이미 NestJS git에서 소스를 받아온 상태라서 먼저 설치를 하고 진행을 한다.

 

인증 시나리오는 

1. 사용자 ID와 PASSWORD로 인증

2. 상태관리를 위한 토큰(jwt) 발급

3. 토큰 유효성 검증

 

$ nest g mo auth
$ nest g s auth

아래는 참고(터미널에서 nest를 입력하면 나온다)

    Available schematics:
      ┌───────────────┬─────────────┬──────────────────────────────────────────────┐
      │ name          │ alias       │ description                                  │
      │ application   │ application │ Generate a new application workspace         │
      │ class         │ cl          │ Generate a new class                         │
      │ configuration │ config      │ Generate a CLI configuration file            │
      │ controller    │ co          │ Generate a controller declaration            │
      │ decorator     │ d           │ Generate a custom decorator                  │
      │ filter        │ f           │ Generate a filter declaration                │
      │ gateway       │ ga          │ Generate a gateway declaration               │
      │ guard         │ gu          │ Generate a guard declaration                 │
      │ interceptor   │ in          │ Generate an interceptor declaration          │
      │ interface     │ interface   │ Generate an interface                        │
      │ middleware    │ mi          │ Generate a middleware declaration            │
      │ module        │ mo          │ Generate a module declaration                │
      │ pipe          │ pi          │ Generate a pipe declaration                  │
      │ provider      │ pr          │ Generate a provider declaration              │
      │ resolver      │ r           │ Generate a GraphQL resolver declaration      │
      │ service       │ s           │ Generate a service declaration               │
      │ library       │ lib         │ Generate a new library within a monorepo     │
      │ sub-app       │ app         │ Generate a new application within a monorepo │
      │ resource      │ res         │ Generate a new CRUD resource                 │
      └───────────────┴─────────────┴──────────────────────────────────────────────┘

auth module과 service를 생성한다.

문서에는 user도 생성하는데 나는 member를 이미 생성해서 넘어 간다.

 

    public async loginMember(loginid: string): Promise<MemberInfo>{
        const member: MemberInfo = await this.memberRepository.findOne({
            where:{
                LOGIN_ID: loginid
            }
        });
        return member;
    }

.

  async validateMember(userid: string, password: string): Promise<any> {
    const user = await this.memberService.loginMember(userid);
    if (user && user.PASSWORD === password) {
      const { PASSWORD, ...result } = user;
      return result;
    }
    return null;
  }
}

userid와 password를 받아 memberService의 loginMember를 호출하여 userid를 던져주고 user(memberInfo)객체를 받아서 받은 user객체의 PASSWORD와 입력 받은 password가 같은지 검사 하여 같으면 user객채를 던저주고 아니면 null을 반환 한다.

 

여기서 받은 비밀번호를 암호화 하지 않았다.

보안에 치명적이다. 나는 실재 서비스 용도로 개발중이니 암호화를 하자 NestJS에서 추천하는것은 bcrypt이다

암호화 부분은 우선 인증을 마치고 다시 작업을 하는것으로....

 

-----------------=========================-----------------------

이제 Passport 로컬 인증 전략을 구현할 수 있습니다 . 

라는 파일 만들기 local.strategy.ts에 auth폴더를 다음 코드를 추가 

-----------------=========================-----------------------

passport를 사용하기 위에 local.strategy.ts를 만들라고 하니 일단 만들어 본다.

 

validate로 authService의 validateMember의 결과를 가져와서 검증을 한다.... 흠..... 

아직까진 모르겠다. 

validateMember 메소드에서 null일때 오류를 반환하면 될것 같은데....

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';
import { AuthService } from '../auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateMember(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

UnauthorizedException를 반환 하는데 알아 보자.

401에러 아.. 네..네....message는 기본으로 unauthored.....어쩌구...자바에서 처럼 에러 메세지를 보낼수 있는거 같다.

 

export declare class UnauthorizedException extends HttpException {
    /**
     * Instantiate an `UnauthorizedException` Exception.
     *
     * @example
     * `throw new UnauthorizedException()`
     *
     * @usageNotes
     * The HTTP response status code will be 401.
     * - The `objectOrError` argument defines the JSON response body or the message string.
     * - The `description` argument contains a short description of the HTTP error.
     *
     * By default, the JSON response body contains two properties:
     * - `statusCode`: this will be the value 401.
     * - `message`: the string `'Unauthorized'` by default; override this by supplying
     * a string in the `objectOrError` parameter.
     *
     * If the parameter `objectOrError` is a string, the response body will contain an
     * additional property, `error`, with a short description of the HTTP error. To override the
     * entire JSON response body, pass an object instead. Nest will serialize the object
     * and return it as the JSON response body.
     *
     * @param objectOrError string or object describing the error condition.
     * @param description a short description of the HTTP error.
     */
    constructor(objectOrError?: string | object | any, description?: string);
}

 

AuthModule에 방금 정의한 Passport 기능을 사용 하도록 구성하기 위해 auth.module.ts 수정

 

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { MemberModule } from '../member.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './strategies/local.strategy';

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

 

!!!!! 추가로 

memberModule에서 MemberService를 exports 해 줘야지 다른 service에서 import시 애러가 안난다.

import { Module } from '@nestjs/common';
import { AuthMemberRepository, MemberRepository } from "./member.repository";
import { TypeOrmModule } from "@nestjs/typeorm";
import { MemberController } from './member.controller';
import { MemberService } from './member.service';

@Module({
    imports: [TypeOrmModule.forFeature([MemberRepository,AuthMemberRepository])],
    controllers: [MemberController],
    providers: [
        MemberService, ],
    exports: [MemberService],
})
export class MemberModule { }

 

 

지금부터 원래 원하였던 인증에 대한 부분이다.

공식 문서에서 Built-in Passport Guards 부터 시작.

잠을 많이 잤는데도 잠이...

지금까지 작업한 내용은 git에 올렸고 

오늘은 여기까지 하고 내일 퇴근하고 다시 시작하자.

 

다음글 

leannet.tistory.com/71

 

NestJS Authentication(2) jwt+환경변수

하루 지났는데 가물가물... 우선 공식 문서에서 local-auth.guard.ts import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() export class LocalAuthGuard..

leannet.tistory.com

 

'Learning > NestJS' 카테고리의 다른 글

NestJS Authentication(4) jwt(수정)  (0) 2021.01.11
NestJS Authentication(3) 환경변수  (0) 2021.01.07
NestJS Authentication(2) jwt+환경변수  (0) 2021.01.06
DTO (Data Transfer Object)  (0) 2021.01.02
NestJS 시작 하다  (0) 2021.01.01