[Node.js] json web token 기반의 Auth 구현

jsonwebtoken

Posted by dongjune on December 15, 2020

이번 포스팅에서는 json web token을 이용한 토큰 기반 user 인증을 구현해보겠습니다.

회원가입 성공시 json web token 받기

다음과 같이 회원가입을 담당하는 router 가 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
router.post(
  "/",
  async (req, res) => {
    const { name, email, password } = req.body;

    try {
      // check user exists
      let user = await User.findOne({ email });
      if (user) {
        return res
          .status(400)
          .json({ errors: [{ msg: "User already exists" }] });
      }

      user = new User({
        name,
        email,
        password,
      });

      // Encrpyt password
      const salt = await bcrypt.genSalt(10);
      user.password = await bcrypt.hash(password, salt);

      await user.save();

      res.send("Register Success");
    } catch (error) {
      console.error(error.message);
      res.status(500).send("Server Error");
    }
  }
);

User의 회원가입에 성공하면 user 정보를 mongoDB에 저장 후 응답으로 Register Success 를 보내주는 api 입니다.

저는 json web token 을 client에게 응답으로 보내주고 싶습니다.

1. jsonwebtoken 패키지 설치

npm 으로 jsonwebtoken 패키지를 설치해줍니다.

1
$ npm i jsonwebtoken

2. jsonwebtoken 사용하기

우선 패키지를 불러와야겠죠.

1
const jwt = require("jsonwebtoken");

이제 user의 id 정보를 jsonwebtoken 으로 변환하여 client에게 response로 보내주겠습니다.

다음의 코드를 위의 회원가입 router에 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const payload = { // json web token 으로 변환할 데이터 정보
  user: {
    id: user.id,
  },
};
// json web token 생성하여 send 해주기
jwt.sign(
  payload, // 변환할 데이터
  "jwtSecret", // secret key 값
  { expiresIn: "1h" }, // token의 유효시간
  (err, token) => {    
    if (err) throw err;
    res.send({ token }); // token 값 response 해주기
  }
);

회원가입 성공시 json web token을 응답해주는 api를 완성했습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const express = require("express");
const bcrypt = require("bcryptjs");
const User = require("../../models/User");
const router = express.Router();
const jwt = require("jsonwebtoken");

// @route  POST api/register
// @desc   Register user
// @access Public
router.post(
  "/",
  async (req, res) => {
    const { name, email, password } = req.body;

    try {
      let user = await User.findOne({ email });

      // check user exists
      if (user) {
        return res
          .status(400)
          .json({ errors: [{ msg: "User already exists" }] });
      }

      user = new User({
        name,
        email,
        password,
      });

      // Encrpyt password
      const salt = await bcrypt.genSalt(10);
      user.password = await bcrypt.hash(password, salt);
      // db에 user 저장
      await user.save();

      // json web token 생성 및 response
      const payload = {
        user: {
          id: user.id,
        },
      };
      jwt.sign(
        payload,            // token으로 변환할 데이터
        "jwtSecret",        // secret key 값
        { expiresIn: "1h" },// token의 유효시간을 1시간으로 설정
        (err, token) => {   
          if (err) throw err;
          res.send({ token });
        }
      );
    } catch (error) {
      console.error(error.message);
      res.status(500).send("Server Error");
    }
  }
);

module.exports = router;

3. Postman으로 token 받기

이제 postman을 사용하여 회원가입 시 token을 잘 보내주는지 확인해보겠습니다.

다음과 같이 Header에서 content type을 json으로 설정해주시고 스크린샷 2020-12-15 오후 3 44 01 회원 가입 정보를 json 형태로 입력후 send 해주면 스크린샷 2020-12-15 오후 3 44 11 서버가 성공적으로 token을 보내주는 것을 확인할 수 있습니다. 스크린샷 2020-12-15 오후 3 44 17

Token으로 User 정보 받아오기

이제 이 받아온 token을 사용하여 DB에 저장된 user 정보를 받아와 보겠습니다.

우선 middleware를 만들어줘야 합니다. 이 middleware를 통해 client가 보내는 token이 유효한지 검사한 후 req에 user 정보를 할당합니다. 다음은 auth middleware의 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const jwt = require("jsonwebtoken");

module.exports = function (req, res, next) {
  // Get token from header
  // header에서 x-auth-token 은 token의 key 값
  const token = req.header("x-auth-token");

  // Check if not token
  if (!token) {
    return res.status(401).json({ msg: "No token, authorization denied" });
  }

  // Verify token
  try {
    // token 해독, token을 만들 때 설정한 secret key 값 : jwtSecret
    const decoded = jwt.verify(token, "jwtSecret");
    // req에 해독한 user 정보 생성 
    req.user = decoded.user;
    next();
  } catch (error) {
    res.status(401).json({ msg: "Token is not valid" });
  }
};

이제 이 미들웨어를 사용하여 user 정보를 받아보겠습니다. 다음은 token을 사용하여 user 정보를 받아오는 router입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const express = require("express");
const router = express.Router();
const auth = require("../../middleware/auth"); // middleware 불러오기
const User = require("../../models/User");
const jwt = require("jsonwebtoken");

// @route  GET api/auth
// @desc   Auth
// @access Public
router.get("/", auth, async (req, res) => {
  try {
    // auth 미들웨어에서 생성해준 req.user를 사용하여 DB에서 user 탐색
    const user = await User.findById(req.user.id).select("-password");
    res.json(user);
  } catch (error) {
    console.error(error.message);
    res.status(500).send("Server error");
  }
});

get 안에 중간에 middleware auth를 넣어준 것을 확인할 수 있습니다.

Postman으로 확인하기

이제 postman에서 token을 request로 보내서 user 정보를 받아보도록 하겠습니다. Header에 위에서 받은 token을 넣어주고 Send를 누르면 스크린샷 2020-12-15 오후 4 22 29 다음과 같이 성공적으로 user 정보를 받아오는 것을 확인할 수 있습니다. 스크린샷 2020-12-15 오후 4 23 55