/** bcrypt 모듈
단방향성 암호화로, 원래의 데이터를 아무도 모르게 만든다.
하지만 저장된 패스워드를 암호화 시키고, 들어온 패스워드를 검증이 한다.
yarn add bcrypt
**/

//데이터 값을 넣을 때 미리 db안에 만들어야 하므로 npx prisma db push를 먼저 하고 npx nodemon 을 하도록 하자.


/** refresh token 리프레쉬 토큰은 로그인 만료 기능을 수행 할 수 있게 만든다. 보안성이 많이 올라간다.
import express from 'express';
import jwt from 'jsonwebtoken';
import cookieParser from 'cookie-parser';

const app = express();
const PORT = 3019;

----비밀키 노출 방지를 위해 .env에 관리 할 것------
const ACCESS_TOKEN_SECRET_KEY = `HangHae99`;
const REFRESH_TOKEN_SECRET_KEY = `Sparta`;

app.use(express.json());
app.use(cookieParser());

const tokenStorages = {};

app.get('/', (req,res) => {
  return res.status(200).send('Hello Token!');
});
-----------엑세스, 리프레시 토큰 발급-----------
app.post('/tokens, async (req,res) => {
  const {id} = req.body; id값을 가져와서,
  const accessToken = jwt.sign({id: id}, ACCESS_TOKEN_SECRET_KEY, {expiresIn: '10s'}); id, 비밀값, 파기날짜 순으로 넣는다.
  const refreshToken = jwt.sign({id: id}, REFRESH_TOKEN_SECRET_KEY, {expiresIn: '7d'});

  tokenStorages[refreshToken] = { 이곳에 tokenUserInfo 임시 저장
    id: id,
    ip: req.ip,
    userAgent: req.headers['user-agent'],
  }

  res.cookie('accessToken', accessToken); 비밀화를 해서 토큰 발급
  res.cookie('refreshToken', refreshToken);

  return res.status(200).json({message: 'Token이 정상적으로 발급되었습니다.'})
});


엑세스 토큰 검증 API 
app.get('/tokens/validate', (req, res) => {
  const accessToken = req.cookies.accessToken; 클라이언트 쿠키값 가져와서

  if (!accessToken) { 쿠키가 없으면?
    return res
      .status(400)
      .json({ errorMessage: 'Access Token이 존재하지 않습니다.' });
  }

  const payload = validateToken(accessToken, ACCESS_TOKEN_SECRET_KEY); 맨 아래에 함수있다. 함수 끝나면 토큰 아니면 빈값
  if (!payload) { 토큰이 이상하면 혹은 만료되면
    return res
      .status(401)
      .json({ errorMessage: 'Access Token이 유효하지 않습니다.' });
  }

  const { id } = payload; 토큰값이 id로 들어감
  return res.json({
    message: `${id}의 Payload를 가진 Token이 성공적으로 인증되었습니다.`,
  });
});

// Token을 검증하고 Payload를 반환합니다.
function validateToken(token, secretKey) {
  try {
    const payload = jwt.verify(token, secretKey);
    return payload;
  } catch (error) {
    return null;
  }
}


리프레시 토큰 검증 API
app.post('/tokens/refresh', (req, res) => {
  const refreshToken = req.cookies.refreshToken; 리프레시 쿠키를 가져온다.

  if (!refreshToken) 쿠키가 없으면,
    return res
      .status(400)
      .json({ errorMessage: 'Refresh Token이 존재하지 않습니다.' });

  const payload = validateToken(refreshToken, REFRESH_TOKEN_SECRET_KEY); 위에랑 동일
  if (!payload) {
    return res
      .status(401)
      .json({ errorMessage: 'Refresh Token이 유효하지 않습니다.' });
  }

  const userInfo = tokenStorage[refreshToken]; 서버에서 유저 정보를 가져온다.
  if (!userInfo) 정보가 없으면,
    return res.status(419).json({
      errorMessage: 'Refresh Token의 정보가 서버에 존재하지 않습니다.',
    });

  const newAccessToken = createAccessToken(userInfo.id); (실수로 만료기간 안 적을 수도 있으니 그냥 함수로 뺄 것)

  res.cookie('accessToken', newAccessToken); 리프레시 토큰이 있으면 액세스 토큰을 새로 받을 수 있다~
  return res.json({ message: 'Access Token을 새롭게 발급하였습니다.' });
});

// Token을 검증하고 Payload를 반환합니다.
function validateToken(token, secretKey) { 토큰이랑 시크릿 키값이 들어오면
  try {
    const payload = jwt.verify(token, secretKey); verify를 이용해 토큰과 비밀값이 유효하면 토큰 리턴, 아니면 에러
    return payload;
  } catch (error) {
    return null;
  }
}
**/


/** 로그 미들웨어 : 코드가 실행되는 각종 정보에 대해 알려준다.
 yarn add winston

import winston from 'winston';

const logger = winston.createLogger({ 로거를 만든다
    level: 'info',
    format: winston.format.json(),
    transport:[
        new winston.transports.Console(),
    ]
});


export default function(req,res,next){
    const start = new Date().getTime(); 스타트는 지금 시간, 명령이 시작됐을때 시간

    res.on('finish', () => { 끝났을 때
        const duration = new Date().getTime() - start; 끝났을때 시간 - 명령 시작했을 때 시간
        logger.info(`Method: ${req.method}, URL: ${req.url}, Status: ${res.statusCode}, Duration: ${duration}ms`);
    });
    next();
}
**/

/** 에러 처리 미들웨어
export default function (err, req, res, next) {
    console.error(err);

    res.status(500).json({message: '서버 내부에서 에러가 발생했습니다.'});
}
이후 route에 try catch 하고 넘겨주는값 next(err)
그리고 app.js 에 import 하고 에러를 전체적으로 처리해주기 위해 마지막에 작성한다.
**/

0개의 댓글

관련 채용 정보