[Nest] Nest WikiDocs (4.14)

ShinJuYong·2022년 4월 15일
0

Nest

목록 보기
7/13
post-thumbnail

미들웨어

Web개발에서 미들웨어라우트핸들러가 클라이언트의 요청을 처리하기전, 수행되는 컴포넌트를 의미한다

라우트핸들러란 Nest.js와같은 프레임워크에서 요청을 처리하는 엔드포인트마다 동작을 수행하는 컴포넌트 (@Get등등..)

Nest.js의 미들웨어

  1. 기본적으로 Express와 동이랗다.
  2. 쿠키파싱 : 쿠키를 파싱해와서 쉬운 데이터 구조로 변경해준다.
  3. 세션관리 : 세션 쿠키를 찾은후, 해당 쿠키에대한 세션상태를 조회후 요청에 세션정보를 추가해준다
  4. 인증/인가 : 사용자가 서비스에 접근가능한 권한이 있는지 확인, Nest에선 Guard를 권장한다
  5. 본문 : 본문은 POST,PUT요청으로 들어오는 JSON형태의 타입뿐만아니라 File과같은 데이터도 있다, 이 데이터를 유형에 따라 읽고 해석한후 파라미터에 넣는 작업

가드

인가(Authorization)은 인증을 통과한 유저가 요청한 기능을 사용할 권한이 있는지를 판별하는 것을 말한다. 퍼미션,롤,ACL과 같은 개념을 사용하여 유저가 가지고 있는 속성으로 리소스 사용을 허용할 지 판별한다.

보통 인증과 인가가 실패할 경우의 응답코드는 401과 403이다

가드의 구현

가드는 CanActivate 인터페이스를 구현해야한다.

canActivate 함수는 ExecutionContext 인스턴스를 인자로 받고, ExcutionContextArgumentsHost를 상속받는데 요청,응답에대한 정보를 가지고 있다
우리는 HTTP로 기능을 제공하기때문에 switchToHttp()함수를 사용하여 필요한 정보를 가져올 수 있다.

이렇게 얻은 정보를 내뷰 규칙으로 평가하는 validateRequest함수를 통해 인가를 진행한다

가드의 적용

컨트롤러나 메소드쪽에서 적용하고자 한다면 @UseGuards(AuthGuard)와 같이 사용한다(데코레이터)
AuthGuard 인스턴스 생성은 Nest가 대신 해준다.
만약, 여러 종류의 가드를 적용하고 싶다면 쉼표로 이어 선언하면 된다

인증

사용자의 정보를 보호하기 위해서는, 서버에 접속하는 클라이언트(유저)가 주인인지 확인을 하는 절차를 거쳐야한다,
사용자가 아이디와 비밀번호로 로그인을 한다면 로그아웃을 할 때 까지 해당 클라이언트가 가진 권한 내에서 서비스를 사용할 수 있다.

즉, 사용자가 가진 정보를 조회하고 변경할 수 있게된다.

세션 기반 인증

세션은 로그인에 성공한 유저가 서비스를 사용하는 동안 저장하고 있는 유저의 정보이다
서버는 세션을 생성하고나서 세션을 DB에 저장하고, 이후 사용자의 요청에 포함된 세션 정보가 세션 DB에 저장되어 있는지 확인한다.

세션방식의 단점은 공격자가 브라우저에 저장된 데이터를 탈취할 수 있다는것.
탈취된 세션을 이용하면 해당 사용자인것 처럼 서버에 접근이 가능하다
이를 방지하기 위해 https로 암호화된 통신을 하거나 세션에 유효시간을 정해둔다.

토큰 기반 인증

세션이 사용자 인증 정보를 서버에 저장하는 방식인 반면, 토큰은 사용자가 로그인 했을 때 서버에서 토큰을 생성한 후, 전달하고 따로 저장소에는 저장을 하지 않는 방식

이후 요청에 대해 클라이언트가 전달한 토큰에 대해 검증을 수행한다,
JWT를 제일 많이사용

유저서비스의 이메일 인증처리와 JWT발급

회원 가입 요청에 포함된 이메일에는 다음 링크가 있엇다

const url = 
      `${baseUrl}/users/email-verify?
		signupVerifyToken=${signupVerifyToken}`;

signupVerifyToken은 회원 가입시에 서버에서 발급한 임의의 문자열로 메일사용자에게 유일한 값이다, 버튼을 누르면 POST로 email-verify엔드포인트로 요청을 보내는데 이 요청을 처리하는것이 이메일 인증처리

Auth등록

Module

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';

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

Service

import { Inject, Injectable } from '@nestjs/common';
import { ConfigType } from '@nestjs/config';
import authConfig from 'src/config/authConfig';
import * as jwt from 'jsonwebtoken';

interface User {
  id: string;
  name: string;
  email: string;
}

@Injectable()
export class AuthService {
  constructor(
    @Inject(authConfig.KEY)
    private config: ConfigType<typeof authConfig>, //
  ) {}

  login(user: User) {
    const payload = { ...user };

    return jwt.sign(payload, this.config.JWT_SECRET, {
      expiresIn: '1d',
      audience: 'example.com',
      issuer: 'example.com',
    });
  }
}

Auth모듈과 서비스를 완성후 이메일인증을요청

JWT 발급에 사용한 비공개 클레임들과 등록된 클레임이 포함된것을 확인가능. lat -> 발급시간(자동 생성)

로그인

  async login(email: string, password: string): Promise<string> {
    // 1. email, password 가진 유저가 db에있다면 처리, 없으면 에러
    const user = await this.usersRepository.findOne({
      where: { email: email, password: password },
    });

    if (!user) {
      throw new NotFoundException('유저가 존재하지 않습니다');
    }
    // 2. JWT를 발급해 전달
    return this.authService.login({
      id: user.id,
      name: user.name,
      email: user.email,
    });
  }

0개의 댓글