[chat] jwt 토큰 발행하기

miin·2022년 5월 10일
0

Skill Collection [Function]

목록 보기
29/45

full code

https://github.com/suminllll/chatting-sample

// jwt.js
const jwtSecret = process.env.JWT_SECRET;
const jwt = require("jsonwebtoken");

const jwtConstants = {
  expiresIn: "7 days", //유효기간
  expires: () => {
    const days = //만료기간 계산
    parseInt(jwtConstants.expiresIn.split(" ")[0]);
    return new Date(Date.now() + 1000 * 60 * 60 * 24 * days);
  },
};

//토큰 발급
function jwtSeriallzer(req, res, next) {
  const token = jwt.sign(
//sign(사용자가 입력한 nick, secret key, 유효기간)
//nick-> login(router)에서 받아오는 키값과 같아야함
    { nick: req.body.nick,}, jwtSecret,
    { expiresIn: jwtConstants.expiresIn,});

  //cookie setting 
  //('name', 'value', { httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 });
  res.cookie("accessToken", token, {
    httpOnly: true, //인증토큰을 보관하는 쿠키는 필수
    signed: true,
    secret: jwtSecret,
    expires: jwtConstants.expires(),
  });

  next();
}

//token 역직렬화
async function jwtDeserializer(req, res, next) {
  //signedCookies: 보안이 추가된 쿠키 cookie와 다름
  //aceesToken = req.signedCookies.에 있는 실제 쿠키이름 
  const accessToken = req.signedCookies.accessToken;
  
  if (!accessToken) {
    return res.status(401).send({
      result: false,
      message: "Access token is not provided",
      data: [],
    });
  }

  //풀어주는 키 (발급키[jwtSecret]와 같아야함) 시크릿만 있으면 다 풀림
  const decoded = jwt.verify(accessToken, jwtSecret);

  const isExpired = decoded.exp < Date.now() / 1000;

  if (isExpired) {
    return res.status(401).send({
      result: false,
      message: "Access token is expired",
      data: [],
    });
  }

  //req.user -> express에서 제공하는 메소드
//req.user.nick으로 get으로 가져올때 nick으로 불러옴{nick: req.user.nick}
  req.user = { nick: decoded.nick };
  res.locals.message = "Access token is valid";

  next();
}

//모듈로 내보내기 
//모듈로 내보낼때는 항상 마지막에 한번에 할당
module.exports = { generateToken, jwtDeserializer };

발급하기

//login.router.js
const express = require("express");
const router = express.Router();
const loginCtr = require("../controller/login");
const { jwtSerializer, jwtDeserializer } = require("../commons/jwt");

//jwtSerializer미들웨어를 파라미터로 받아옴 === token을 같이 받아옴
router.post("/add", jwtSerializer, async function (req, res, next) {
  const reqData = { 
    nick: req.body.nick, //클라에서 받아온 nick
  };

  // nick 중복 검사
  // getLogin으로 해당 nick이 있는지 쿼리를 날려보고 있으면 여기서 return,
  //없으면 아래 로직으로 넘어감
  const getMemberFromNick = await loginCtr.getLogin(reqData);
  if (getMemberFromNick.success) {
    return res.status(getMemberFromNick.http_status).send(getMemberFromNick);
  }

  //nick이 없으면 실행됨 (db에 추가)
  const resData = await loginCtr.addLogin(reqData);

  return res.status(resData.http_status).send(resData);
});

//login.controller.js
const loginCtr = {};

//회원가입 또는 처음 로그인
loginCtr.addLogin = async (_reqData) => {
  let inputSql, outputSql;
  inputSql = `INSERT INTO member(nick, joined) VALUES(:nick, now())`;
  outputSql = await _db.qry(inputSql, _reqData);
  
  if (!outputSql.success) return _res.internalServerErr();

  return _res.created(outputSql.result.insertId);
};

조회하기

//login.router.js
//쿠키를 해석해서 가져옴
router.get("/info", jwtDeserializer, async (req, res) => {
  const reqData = {
    nick: req.user.nick, //jwtDeserializer에서 가져온 nick
  };

  const resData = await loginCtr.getLogin(reqData);

  return res.status(resData.http_status).send(resData);
});


//login.controller.js
const loginCtr = {};

//해당 nick의 정보를 가져옴
loginCtr.getLogin = async (_reqData) => {
  let inputSql, outputSql;
  inputSql = `SELECT * FROM member WHERE nick = :nick`;

  outputSql = await _db.qry(inputSql, _reqData);

  if (!outputSql.success) return _res.internalServerErr();

  console.log(outputSql);
  return _res.okData(outputSql.result);
};

로그아웃

router.post("/logout", async (req, res) => {
  return res.clearCookie("accessToken").status(200).send({});
});

0개의 댓글