[Node.js] access token, refresh token 을 활용하여 로그인 유지시키기

2022. 8. 16. 18:10·개발/node.js
728x90
반응형

1. access token, refresh token 을 활용하여 로그인 유지시키기

// express, dotenv, fs, jsonwebtoken , express-session, mysql2
// 개발용으로 nodemon

// 모듈 설치

//fs 모듈 가져오기
const fs = require("fs");

//express 모듈 가져오기
const express = require("express");

// .env파일을 사용하기 위해 가져오면서 설정
const dot = require("dotenv").config();

// jsonwebtoken 모듈 가져오기
const jwt = require("jsonwebtoken");

//express-session 모듈 가져오기
const session = require("express-session");
const FileSotre = require("session-file-store")(session);

// mysql2 모듈 가져오기
const mysql = require("mysql2");
//mysql 로컬 데이터 베이스 연결
//mysql createConnection 함수를 이용해서 연결 및 생성
const client = mysql.createConnection({
  // 데이터 베이스 계정의 이름
  user: "root",
  //계정의 비밀번호
  password: "kga22C3_05^",
  //연결할 데이터 베이스의 이름
  database: "test7",
  //multipleStatements 다중 쿼리문을 사용할수 있도록 하는 옵션
  multipleStatements: true,
});

// 서버 객체 생성
const app = express();

//req.body 객체를 사용할거니까
// express 버전업 되면서 express설정으로 body 객체를 사용하게 설정할수 있다.
app.use(express.urlencoded({ extended: false }));

//세션도 사용
app.use(
  session({
    //세션 발급할때 사용되는 키 : 노출되면 안되니까 .env파일에 값을 저장해놓고 사용
    secret: process.env.SESSION_KEY,
    //세션을 저장하고 불러올때 세션을 다시 저장할지 여부
    resave: false,
    //세션에 저장할때 초기화 여부를 설정
    saveUninitialized: true,
    store: new FileSotre(),
  })
);

app.get("/", (req, res) => {
  fs.readFile("view/login.html", "utf-8", (err, data) => {
    // login.html 파일을 utf-8 인코딩을 해서 send함수를 이용해서 data를 보내줌(요청을 응답해줌)
    res.send(data);
  });
});

app.get("/join", (req, res) => {
  fs.readFile("view/join.html", "utf-8", (err, data) => {
    // join.html 파일을 utf-8 인코딩을 해서 send함수를 이용해서 data를 보내줌(요청을 응답해줌)
    res.send(data);
  });
});

// id는 AUTO_INCREMENT PRIMARY KEY 컬럼 값을 추가하지 않아도 자동으로 증가하는 숫자
// user_id 이름으로 컬럼을 만들고 VARCHAR(255) 문자 255자 까지 허용
// const sql =
//   "create table users (id INT AUTO_INCREMENT PRIMARY KEY,user_id VARCHAR(255), password VARCHAR(255), refresh VARCHAR(255))";
// // client 객체안의 query 함수로 쿼리문 실행
// client.query(sql);

app.post("/join", (req, res) => {
  //req.body 객체가 있는 키값으로 변수에 할당
  // req.body.userId가 userId에 담긴다.
  //req.body.password도 password 담긴다.
  // {요 안에 키값} 객체 구문으로 묶어서 변수를 받으면 해당 객체의 키값의 벨류를 받을수 있다.
  const { userId, password } = req.body;

  //쿼리문 INSERT INTO users = users 테이블에 추가한다
  //값을 넣어서 추가하는 컬럼은 user_id, password 두개
  //VALUES(?,?)값의 벨류는 옵션으로 전달한다.
  const sql = "INSERT INTO users (user_id,password)VALUES(?,?)";
  //VALUES(?,?) 순서대로 [userId, password] 값 전달
  client.query(sql, [userId, password], () => {
    //redirect 함수로 매개변수 url 해당 경로로 이동시켜준다.
    res.redirect("/");
  });
});

app.post("/login", (req, res) => {
  const { userId, password } = req.body;
  //SELECT * FROM users => users 테이블을 찾고
  // WHERE user_id=? => users 테이블에서 user_id 값으로 검색
  const sql = "SELECT * FROM users WHERE user_id=?";
  client.query(sql, [userId], (err, result) => {
    if (err) {
      res.send("계정 없음");
    } else {
      //result[0]에 값이 있으면 계정이 존재한다는 뜻. 아니면 계정이 없다.
      // ?. 구문 뒤에 키값이 잇는지 먼저보고 값을 참조한다. 그래서 없으면 터지는 일을 방지

      if (result[0] && password === result[0]?.password) {
        //로그인 성공했으니까 토큰 발급
        // access token 발급
        const accessToken = jwt.sign(
          {
            //payload 값 전달할 값
            userId: result[0].user_id,
          },
          //ACCESS_TOKEN 비밀키
          process.env.ACCESS_TOKEN,
          {
            //유효 기간 5초
            expiresIn: "5s",
          }
        );

        //refresh token 발급
        const refreshToken = jwt.sign(
          {
            userId: result[0].user_id,
            mail: "dasdfad@naver.com",
            name: "dfja",
          },
          process.env.REFRESH_TOKEN,
          {
            expiresIn: "1m",
          }
        );
        //UPDATE users SET = user 테이블의 refresh 값을 수정
        // WHERE user_id=? => = user_id 값으로 감색

        const sql = "UPDATE users SET refresh=? WHERE user_id=?";
        client.query(sql, [refreshToken, userId]);
        //세션이 accesstToken
        req.session.access_token = accessToken;
        // 세션에 accessToken 값을 access_token키값에 벨류로 활당
        req.session.refresh_token = refreshToken;
        res.send({ access: accessToken, refresh: refreshToken });
      } else {
        res.send("계정 없음");
      }
    }
  });
});

//미들웨어란
// 로그인을 해서 어서오세요 환영합니다 로그인이 유지되어 있는 페이지에 접속하고
// 로그인이 유지되고 있는 동안에만 동작해야하는 페이지들이 있는데, 로그인 유지를 확인하고 요청을 보내야 한다.
// 어떻게 해야하나
// 미들웨어란 간단하게 클라이언트에게 요청이 오고 그 요청을 보내기 위해 응답하는 중간(미들)에 목적에 맞게 처리해주는 중간단계 통과하는 미들웨어 함수이다.
// 요청의 응답에 도달하기 위해서 미들웨어를 통과해야지 응답까지 도달할 수 있다.
// 중간에 문지기 얘의 허락을 맡아야 지나갈수 있다. 엑세스 권한
// req(요청)객체, res(응답) 객체, next()함수를 이용해서 통과 요청을 넘길수 있다.
// 너지나가 = next();
// 문지기 통과 next지나가세요
// 요청을 처리하기전에 중간에 기능을 동작시켜주는 애

//매개변수는 (요청객체, 응답객체, next함수)
const middleware = (req, res, next) => {
  // const accessToken = req.sessin.access_token
  // const refreshToken = req.session.refresh_token
  const { access_token, refresh_token } = req.session;
  //access_token 값을 먼저 검증한다. 유효기간이 끝나지 않았는지
  jwt.verify(access_token, process.env.ACCESS_TOKEN, (err, acc_decoded) => {
    //썩은 토큰이면
    if (err) {
      //여기서 로그인 페이지로 넘긴다던지
      // 404 500 에러페이지를 만들어서 보여준다던지
      // 본인의 방향성으로 페이지 구성 하시면 됩니다.
      jwt.verify(
        refresh_token,
        process.env.REFRESH_TOKEN,
        (err, ref_decode) => {
          if (err) {
            res.send("다시 로그인 해주세요");
          } else {
            const sql = "SELECT * FROM users WHERE user_id=?";
            client.query(sql, [ref_decode.userId], (err, result) => {
              if (err) {
                res.send("데이터 베이스 연결을 확인해주세요");
              } else {
                if (result[0].refresh == refresh_token) {
                  const accessToken = jwt.sign(
                    {
                      userId: ref_decode.userId,
                    },
                    process.env.ACCESS_TOKEN,
                    {
                      expiresIn: "5s",
                    }
                  );
                  req.session.access_token = accessToken;
                  // 다음 콜백 실행
                  next();
                } else {
                  res.send("다시 로그인하세요");
                }
              }
            });
          }
        }
      );
    } else {
      //썩지않고 좋은 토큰이면
      console.log(acc_decoded);
      next();
      //다음번 콜백 함수 실행
      // next();
      // access token 이 만료 되었으면
    }
  });
};

//middleware이 미들 웨어 함수에서 next() 함수를 사용하지 못하면
// 다음 콜백함수는 실행되지 않는다.
// 문지기한테 막힌거임
// next()함수를 실행하면 다음 콜백으로 이동해서 요청 및 응답 작업 동작을 한다.
// 로그인이 되어있는 페이지만 요청과 응답을 할수 있게
app.get("/check", middleware, (req, res) => {
  res.send("로그인 되어 있음");
});

app.listen(3000, () => {
  console.log("server start");
});
728x90
반응형

'개발 > node.js' 카테고리의 다른 글

[Node.js] 로그인 만들기  (1) 2022.08.18
[Node.js] crypto, bcrypto  (0) 2022.08.17
[Node.js] 로그인 Access Token, Refresh Token  (0) 2022.08.16
[Node.js] exports router  (0) 2022.08.10
[Node.js] 로그인시 jwt과 session  (0) 2022.08.09
'개발/node.js' 카테고리의 다른 글
  • [Node.js] 로그인 만들기
  • [Node.js] crypto, bcrypto
  • [Node.js] 로그인 Access Token, Refresh Token
  • [Node.js] exports router
TeTedo.
TeTedo.
  • TeTedo.
    TeTedo 개발 일기
    TeTedo.
  • 전체
    오늘
    어제
    • 분류 전체보기 (319)
      • 개발 (274)
        • Article (4)
        • 정리 (21)
        • Spring Boot (17)
        • JPA (2)
        • JAVA (6)
        • Database (4)
        • 자료구조 (11)
        • 알고리즘 (32)
        • React (20)
        • Docker (10)
        • node.js (18)
        • Devops (11)
        • Linux (4)
        • TypeScript (3)
        • Go (10)
        • HyperLedger (4)
        • BlockChain (43)
        • html, css, js (48)
        • CS (3)
        • AWS (3)
      • 모아두고 나중에 쓰기 (3)
      • 팀프로젝트 (18)
        • SNS(키보드워리어) (9)
        • close_sea (9)
      • 개인프로젝트 (1)
        • Around Flavor (1)
        • CHAM (13)
        • ethFruitShop (5)
      • 독서 (0)
        • 스프링부트와 AWS로 혼자 구현하는 웹 서비스 (0)
  • 블로그 메뉴

    • 홈
    • 개발일기
    • CS
    • 실습
    • 코딩테스트
    • 웹
    • Go
    • node.js
    • 팀플
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    블록체인
    30일 챌린지
    erc20
    nodejs
    컨테이너
    명령어
    30일챌린지
    CSS
    node.js
    ERC721
    mysql
    React
    도커
    html
    go
    js
    go언어
    node
    프로그래머스
    하이퍼레저
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
TeTedo.
[Node.js] access token, refresh token 을 활용하여 로그인 유지시키기
상단으로

티스토리툴바