본문 바로가기
JS/Node.js

TIL(23.06.22) .env 설정 / refreshToken 생성

by 썸맨 2023. 6. 24.

★ 프로젝트 development

Lv2) checkObjectId 함수를 미들웨어로 작성해 해당 라우터 앞에 넣어서 미리 데이터 형식의 유효성 검사를 실시

const { ObjectId } = require("mongoose").Types;
 
module.exports = (req, res, next) => {
  const { postId } = req.params;
  try {
    if (!ObjectId.isValid(postId)) throw Error("데이터 형식이 올바르지 않습니다.");
    next();
  } catch (error) {
    return res.status(412).json({ success: false, errorMessage: error.message });
  }
};

 

Lv 3) config.json 파일에 내 개인적인 DB정보가 담겨있어 문제점 발생 => 상훈님과 같이 프로젝트를 develop 하고 있었는데 그 분이 config.json정보를 그대로 github에 push 했더니, 해킹봇에 의해서 DB가 막히고 이메일을 열어보라 하는 메시지가 안에 들어있었음... (나도 올렸었는데 비밀번호를 어렵게 해놓아서 해킹당하진 않았으나  바로 변경)

  • 1. npm install dotenv 로 dotenv 라이브러리 받기
  • 2. .env 환경변수 폴더를 만들어 그 안에 내가 은닉할 정보의 환경변수를 만듬
MYSQL_USERNAME= "실제 이름의 값"
MYSQL_PASSWORD= "실제 비밀번호의 값"
MYSQL_HOST= "실제 연결된 주소"
  • 3. 해당 환경변수를 적용하기 위해 config.json을 config.js로 변환 후 변수들로 만들어 module.exports로 내보내준다.
require("dotenv").config();
const env = process.env;

const development = {
  username: env.MYSQL_USERNAME,
  password: env.MYSQL_PASSWORD,
  database: env.MYSQL_DATABASE,
  host: env.MYSQL_AWS_HOST,
  dialect: "mysql",
};
//production / test 도 만들어져 있음 (생략)
module.exports = { development, production, test };
  • 4. 마지막으로 이 config를 사용하는 models 폴더의 index.js에서의 경로만 바꿔주면 해결!
//.models/index.js 
const config = require(__dirname + "/../config/config.js")[env];

=> 이전에 이미 .gitignore파일을 만들어서 git push 할 때 올라가지 않는 부분을 만들었으므로 따로 설정하지 않았음(gitignore.io 사이트에서 node환경으로 받은 내용 안에 .env가 포함이 되어 있기 때문에!)

 

Lv3 ) 필수 구현사항을 전부 구현하고 상훈님과 추가적으로 development

  • 쿠키가 유지가 되었을 때의 로그인 유지뿐만 아니라 쿠키가 삭제가 되더라도 사용자 정보를 저장하게 된다면 로그인 유지가 지속적으로 되는 과정을 develop하려 함 -> refreshToken을 생성
  • 알고리즘 구상 1) 로그인을 한다면 해당 유저의 accessToken이 생성이 되면서 동시에 refreshToken도 생성을 해 DB에 이 토큰을 저장(accessToken보다 만료기한을 길게 함 - 보통 14일로 설정한다 함) 
  • 2) 이 때 만약 유저의 accessToken이 만료가 되거나 쿠키가 삭제가 되어서 다시 로그인을 해야 하는 상황이 온다면 바로 로그인 하도록 안내하는 게 아닌 DB에 저장이 되어 있는 refreshToken을 가져와 해당 토큰을 검증해 유효기간이 만료가 되지 않았다면 새 accessToken을 발급해 주는 걸로 로그인이 유지되도록 함.(해당 refreshToken도 만료가 되었다면 새로 로그인 하도록 안내)
  • 3) 한 번에 한 사용자만 로그인 유지가 되어야 하므로 해당 사용자가 아닌 다른 사용자가 로그인을 했었을 경우에는 원래 DB에 담긴 refreshToken을 지우고 새로운 사용자의 userId가 담긴 refreshToken을 발급 해서 저장함.

※ 구현

      const refreshToken = jwt.sign({}, process.env.JWT_SECRET_KEY, { expiresIn: "14d" });
      const accessToken = jwt.sign({ userId: user.userId }, process.env.JWT_SECRET_KEY, {
        expiresIn: "1h",
      });
 
      await Tokens.destroy({ where: { UserId: user.userId } });
      await Tokens.create({ tokenId: refreshToken, UserId: user.userId });
      res.cookie("accessToken", `Bearer ${accessToken}`);

=> login router 에 추가, 기존에 하나의 토큰만 발급이 되어 쿠키에 저장이 되었다면 refreshToken도 발급을 해서 저장 ( 이 때 기존의 refreshToken이 있는지 체크해서 만약 있을 때, 해당 로그인하는 userId와 DB에 저장된 userId가 같을 경우는 destory / create를 하지 않고 accessToken만 생성했고 두 userId가 다르다면 새로운 userId의 refreshToken을 생성하도록 제약 조건을 이후에 추가 함!)

 

    const existReFreshToken = await Tokens.findOne({ });
    if (existReFreshToken.tokenId.length !== 0 && !accessAuthType && !accessAuthToken) {
      jwt.verify(existReFreshToken.tokenId, process.env.JWT_SECRET_KEY);

      const accessToken = jwt.sign(
        { userId: existReFreshToken.UserId },
        process.env.JWT_SECRET_KEY,
        {
          expiresIn: "1h",
        }
      );

      res.cookie("accessToken", `Bearer ${accessToken}`);
      const user = await Users.findOne({ where: { userId: existReFreshToken.UserId } });

      if (!user) {
        res.clearCookie("accessToken");
        return res
          .status(403)
          .json({ success: false, errorMessage: "토큰 사용자가 존재하지 않습니다." });
      }

      res.locals.user = user;
      res.locals.userNickname = user.nickname;
      next();
    }

=> auth-middleware.js에 추가, refreshToken이 있다면 해당 토큰을 검증해서 검증이 되었을 때 새로운 accessToken을 발급해서 쿠키에 저장하도록 설정

 

☆☆주의 : jwt를 검증을 했었을 때, 해당 토큰이 만료가 되었다면 시스템 오류가 발생

 - 문제 해결 : 1) try~catch문으로 감싸서 해당 에러에 대한 예외처리를 해줌  2) verify 내의 콜백함수에 예외처리를 해줌

 // 여기서 나는 try~catch 구문으로 감싸서 해결

} catch (error) {
    if (error.name === "TokenExpiredError") {
      if (existReFreshToken)
        await Tokens.destroy({ where: { } });

      res.status(403).json({
        success: false,
        message: "토큰이 만료된 아이디입니다. 다시 로그인 해주세요.",
      });
      return;
    }

=> 해당 토큰이 만료가 되었다면 삭제를 하면서 토큰이 만료되었으니 다시 로그인 해달라는 메시지를 반환 함.

 

'JS > Node.js' 카테고리의 다른 글

TIL(2023.06.27)  (0) 2023.06.29
Node.js 숙련  (0) 2023.06.25
TIL(23.06.23) refreshToken을 활용한 유저 계정 전환 기능  (0) 2023.06.24
TIL(23.06.21) - 게시글 / 댓글 RestAPI 구현  (0) 2023.06.22
Node.js 입문  (0) 2023.06.20