Serverless Sessions(1)

yonghee·2022년 6월 14일
0

baechu-market

목록 보기
21/32

iron session

https://github.com/vvo/iron-session

iron-session은 암호화된 쿠키를 이용하는 Node.js stateless(무상태) session utility 입니다. JWT와 비슷하지만, 전송되는 토큰 정보(payload)를 암호화 한다는 점에서 차이가 있습니다.

payload 생성
payload를 암호화한다.
쿠키로 전송 (쿠키는 client에서 server로 요청을 보낼때 마다 같이 전송됨)
쿠키를 받아 복호화하고 payload 조회

user에게 쿠키를 주고 유저가 요청을 보냈을 때 누군지 알 수 있도록 할 것인데 iron-session을 이용 할 것이다.

iron-session ex)

{
id:1
}
-----> encrypt ------> asasdfasdfasdf

asasdfasdfasd ------> decrypt -----> { id:1 }

우리가 user 정보를 가진 객체를 만들면(token의 유무 판단) 이 payload를 암호화하게 된다.
그리고 이 암호화 된 정보를 user에게 쿠키로 전송하게 된다. 쿠키는 user가 백엔드로 요청을 보낼 때 마다 요청과 함께 전송 될 것이다. 우리가 쿠키를 받게 되면 쿠키를 복호화(암호문을 평문으로 변환하는 과정)하고 페이지를 접근하려는 유저의 id가 1인지 확인하는 것이다.

JWT와는 다른점

이것은 JWT와는 다른점 JWT는 암호화 되지 않고 서명이 되었을 뿐이다.
JWT는 user의 id를 가진 객체에 서명하고 이 서명과 함께 user에게 token을 보내는 것이다.

{
id:1
}
-----> sign ------> {id:1, signature:abc}

{id:1, signature:abc} ------> check sign -----> { id:1 }
user는 토큰을 받아서 살펴볼 수 있다. 유저가 JWT 토큰 안에 있는 정보를 훤히 알아볼 수 있다. 유저가 JWT를 보냈을 때 우리는 서명을 확인하고 그 token을 신뢰하는 형태이다.

또한 세션을 위한 백엔드를 구축할 필요가 없다는 것이다.

동작 방식

  1. 브라우저가 서버에 요청을 보냄.
  2. 서버에서 정보를 암호화한 쿠키를 만듦.
  3. 브라우저에게 응답을 보낼때 쿠키를 같이 보냄.
  4. 브라우저는 암호화된 쿠키를 가지고, 이후 요청에 쿠키가 같이 보내짐.
  5. 암호화된 쿠키를 받은 서버는 이를 복호화해 정보를 활용함.

여기에서 쿠키를 만들고, 브라우저에게 보내는 등의 작업을 저희가 직접 할 필요가 없습니다. 이 작업들을 도와주는 helper function들을 Iron Session에서 제공합니다.

Install

npm i iron-session

withIronSessionAPIRoute

이 함수를 설명하기 전에, /api 폴더 내에 id가 1번인 user의 정보를 주는 API handler 함수를 다음과 같이 만들 수 있습니다. findUser 함수는 DB에서 id에 해당하는 user를 찾는 함수입니다.

import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const id = 1;
  const foundUser = findUser(id);

  res.json({ ok: true, foundUser });
}

여기에서 id가 1번인 user가 아니라 현재 로그인 되어있는 user의 정보를 얻어 오려면 어떻게 해야할까요? 요청에서 id를 가져오는 작업이 필요하겠죠. 이를 도와주는 함수가 withIronSessionAPIRoute 입니다. 다음과 같이 코드를 변경해 봅시다.

import { NextApiRequest, NextApiResponse } from "next";
import { withIronSessionApiRoute } from "iron-session/next";
import { IronSessionOptions } from "iron-session";

const options: IronSessionOptions = {
  cookieName: "reservation-site",
  password:
    "VERYYLONGPASSWORDS1ab1323898esda345q6781!",
};

async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const id = req.session.user.id;
  const foundUser = await findUser(id);

  res.json({ ok: true, foundUser });
}

export default withIronSessionApiRoute(handler, options);

이 함수의 두 인자는 다음과 같습니다.

  1. handler: 기존 API 핸들러 함수
  2. options: IronSessionOptions 타입 객체. 쿠키 및 패스워드 정보를 가지고 있음
  • 2.1. cookieName: 브라우저에 저장되는 쿠키의 이름
  • 2.2. password: 32자 이상의 비밀번호. 데이터 암호화/복호화에 사용
    위와 같이 기존 handler 함수를 인자로 받습니다. 즉, withIronSessionApiRoute 함수가 handler 함수를 감싸는 형태라고 생각하시면 됩니다. 이렇게 감쌀 경우, handler 함수 내부에서 다음과 같이 session을 사용할 수 있게 됩니다. 또한 세션 정보를 이용하는 것 외에 handler 함수의 동작을 변경하지는 않습니다.

const id = req.session.user.id;
요청의 쿠키에 user가 저장되어 있는 경우 위 코드와 같이 req.session을 이용해 가져올 수 있습니다.

TypeScript

만약 위 코드를 그대로 사용했다면 타입스크립트가 에러를 띄울 것 입니다. 세션 내의 데이터에 대한 정보를 타입스크립트는 모르기 때문입니다. 세션 데이터 타입 작성하는 법에 따라 다음과 같이 declare module 명령어를 이용해 작성합니다.

declare module "iron-session" {
  interface IronSessionData {
    user?: {
      id: number;
    };
  }
}

다만 이 경우에는 세션의 user가 undefined가 될 수 있으므로 id를 가져올 때 session의 유저가 있는지 확인해주는 작업을 추가해주면 됩니다.

const id = req.session.user ? req.session.user.id : 1;

Save

지금까지 세션에서 데이터를 어떻게 가져오는지에 대해서만 얘기했습니다. 이번에는 세션에 데이터를 어떻게 저장하는지에 대해 알아 봅시다.

POST 요청이 들어왔을 때, 요청에서 userId를 추출해서 세션에 저장하는 코드는 다음과 같습니다.

if (req.method === "POST") {
  const {
    body: { userId },
  } = req;
  
  // Assign value
  req.session.user = {
    id: +userId,
  };
  
  // Save at a session
  await req.session.save();
  
  res.json({ ok: true });
}

위와 같이 세션에 값을 할당한 후 save() 함수를 실행시킵니다. 이러면 데이터가 세션에 저장될 뿐만 아니라, 이후에 응답을 보낼때 해당 정보가 암호화되어 쿠키로 브라우저에 보내 집니다.

이후 다른 요청이 들어오면, 그 요청에는 지금 저장한 정보가 쿠키에 실려서 같이 올 것입니다.

그러면 이렇게 암호화 된 쿠키값을 확인 할 수 있다!!

profile
필요할 때 남기는 날것의 기록 공간

0개의 댓글