NestJS/NestJS 기본강의

NestJS 기본강의 - 4. 인증

PHM 2022. 7. 8. 18:32

CLI를 이용한 모듈, 컨트롤러, 서비스 생성

- nest g module auth

    ㆍauth 모듈 생성

- nest g controller auth --no-spec

    ㆍauth 컨트롤러 생성

- nest g service auth --no-spec

    ㆍauth 서비스 생성

 


- 비밀번호 암호화

bcryptjs

npm install bcryptjs --save
import * as bcrypt from 'bcryptjs';

 

비밀번호를 데이터베이스에 저장하는 방법

1. 원본 비밀번호를 저장 (최악)

 

2. 비밀번호를 암호화 키 ( Encryption Key )와 함께 암호화 ( 양방향 )

- 어떠한 암호를 이용해서 비밀번호를 암호화하고 그 암호를 이용하여 복호화도 가능

- 암호화 키가 노출되면 알고리즘은 대부분 오픈되어있기 떄문에 위험도가 높음

 

3. SHA256등 Hash로 암호화해서 저장 ( 단방향 )

- 암호화만 존재, 복호화가 없음

- 레인보우 테이블을 만들어서 암호화된 비밀번호를 비교해서 비밀번호를 알아냄

 

4. 솔트(salt) + 비밀번호(Plain Password)를 해시Hash로 암호화해서 저장

- 암호화할 때 원래 비밀번호에다 salt를 붙인 후에 해시로 암호화를 한다.

import * as bcrypt from 'bcryptjs';

    const salt = await bcrypt.getSalt();
    const hashedPassword = await bcrypt.hash(password, salt);
    const user = this.create({ username, password: hashedPassword });

JWT

- JWT( JSON Web Token )는 당사자간에 정보를 JSON 개체로 안전하게 전송하기위한 컴팩트하고 독립적인 방식을 정의하는 개방형 표준(RFC 7519)이다. 이 정보는 디지털 서명이되어 있으므로 확인하고 신뢰할 수 있다

- 간단히 애기하자면 정보를 안전하게 전할 때 혹은 유저의 권한 같은 것을 체크를 하기 위해서 사용하는데 유용한 모듈

 

JWT의 구조

- Header : 토큰에 대한 메타 데이터를 포함하고 있다

                 ( 타입, 해싱 알고리즘 SHA256, RSA ... )

- Payload : 유저 정보(issuer), 만료 기간(expiration time), 주제(subject) 등등...

- Verify Signature : JWT의 마지막 세그먼트는 토큰이 보낸 사람에 의해 서명되었으며 어떤 식으로든 변경되지 않았는지 확인하는데 사용되는 서명이다.

서명은 헤더 및 페이로드 세그먼트, 서명 알고리즘, 비밀 또는 공개 키를 사용하여 생성

 

* 클라이언트에서 온 Headers + 클라이언트에서 온 Payload + 서버에서 가지고 있는 Secret Text 와

클라이언트에서온 Verify Signature을 비교

 

 

- JWT 모듈 + Passport모듈 ( JWT를 이용해서 인증 처리하는 등의 과정을 쉽게 만듬 )

필요한 모듈 설치

- @nestjs/jwt

    ㆍnestjs에서 jwt를 사용하기 위해 필요한 모듈

- @nestjs/passport

    ㆍnestjs에서 passport를 사용하기 위해 필요한 모듈

- passport

    ㆍpassport 모듈

- passport-jwt

    ㆍjwt모듈

npm install @nestjs/jwt @nestjs/passport passport passport-jwt --save

 

@Module({
  imports: [
    JwtModule.register({
        secret: 'Secret1234'
        signOptions: {
            expiresIn : 60*60,
        }
    }),
})

- Secret : 토큰을 만들 때 이용한 Secret 텍스트

- ExpiresIn : 정해진 시간 이후에는 토큰이 유효하지 않게 됩니다. 60 * 60은 한 시간 이후에는 이 토큰이 더 이상 유효하지 않게 된다.

 

Passport

- @types/passport-jwt 모듈 ( passport-jwt 모듈을 위한 타입 정의 모듈 )

npm install @types/passport-jwt --save

NestJS에서 Middleware들에 대해서

NestJS에는 여러가지 미들웨어가 있다

- Pipes, Filters, Guards, Interceptors 등의 미들웨어로 취급되는 것들이 있는데 각각 다른 모적을 가지며 사용되고 있다.

 

Pipes

- 파이프는 요청 유효성 검사 및 페이로드 변환을 위해 만들어진다.

- 데이터를 예상한 대로 직렬화한다.

 

Filters

- 필터는 오류 처리 미들웨어이다

- 특정 오류 처리기를 사용할 경로와 각 경로 주변의 복잡성을 관리하는 방법을 알 수 있다

 

Guards

- 가드는 인증 미들웨어이다

- 지정된 경로로 통과할 수 있는 사람과 허용되지 않는 사람을 서버에 알려준다

 

Interceptors

- 인터셉터는 응답 매핑 및 캐시 관리와 함께 요청 로깅과 같은 전후 미들웨어이다

- 각 요청 전후에 이를 실행하는 기능은 매우 강력하고 유용하다

 

가각의 미들웨어가 불러지는(called) 순서

middleware → guard → intercerptor(before) → pipe → contoller → service

                   → controller → interceptor(after) → filter ( if applicable ) → client

 

 


UseGuards

- UseGuards 안에 @nestjs/passport에서 가져온 AuthGuard() 를 이용하면 요청안에 유저 정보를 넣어줄 수 있다

  ( req안에 jwt.strategy.ts 파일의 validate의 return값인 user 을 넣어줄 수 있다 )

@Post('/authTest')
@UseGuards(AuthGuard())
authTest(@Req() req) {
    console.log(req);
]

 

* 뭔가 spring security 처럼 UseGuards가 PassportStrategy를 찾아가는 거 같음...?

 


req.user가 아닌 바로 user라는 파라미터를 가져올 수 있는 방법은??

- 커스텀 데코레이터

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { User } from './user.entity';

export const GetUser = createParamDecorator(
  (data, ctx: ExecutionContext): User => {
    const req = ctx.switchToHttp().getRequest();
    return req.user;
  },
);

- 사용 방법

  @Post('/test')
  @UseGuards(AuthGuard())
  test(@GetUser() user: User) {
    console.log('user', user);
  }