[NodeJS] 6장 인증 및 보안

1. JWT(JSON Web Token) 

JWT는 JSON 객체를 사용해 정보를 안전하게 전송하기 위한 개방형 표준(RFC 7519)이며, JWT는 다음과 같은 세 부분으로 구성됩니다.

  • Header: 토큰의 유형(type)과 서명 알고리즘(algorithm)에 대한 정보를 포함
  • Payload: 사용자 정보 및 토큰의 유효 기간과 같은 클레임(claims)을 포함
  • Signature: Header와 Payload를 인코딩한 후 비밀 키를 사용해 서명, 이 서명은 토큰의 무결성을 확인하는 데 사용

JWT는 서버에 상태를 저장할 필요 없이 클라이언트와 서버 간의 인증을 가능하게 합니다.


2. 사용자 인증 구현

먼저 필요한 패키지를 설치하기 위해 아래 명령어를 입력합니다.

npm install express jsonwebtoken bcryptjs dotenv

 

// server.js
const express = require("express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
const dotenv = require("dotenv");

dotenv.config();

const app = express();
app.use(express.json());

const users = []; // 사용자 정보를 저장할 배열

 

다음 사용자 정보를 등록하기 위해 다음 코드를 작성합니다.

// 사용자 등록
app.post("/register", async (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);
  users.push({ username, password: hashedPassword });
  res.status(201).send("User registered");
});

 

다음 사용자 로그인을 구현하는 코드를 작성합니다.

app.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const user = users.find((u) => u.username === username);
  if (!user) return res.status(400).send("User not found");

  const isValid = await bcrypt.compare(password, user.password);
  if (!isValid) return res.status(403).send("invalid password");

  const token = jwt.sign({ username: user.username }, process.env.JWT_SECRET, {
    expiresIn: "1h",
  });
  res.json({ token });
});

 

다음 인증 미들웨어와 인증된 라우트를 작성합니다.

const authenticateJWT  = (req, res, next) => {
  const token = req.headers["authorization"]?.split(" ")[1];
  if (!token) return res.sendStatus(408);

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};
// 인증된 라우트
app.get("/dashboard", authenticateJWT, (req, res) => {
  res.send(`Welcome ${req.user.username}`);
});

3.Helmet 사용

Helmet은 Express 애플리케이션의 보안을 강화하기 위한 미들웨어입니다. HTTP 헤더를 설정하여 여러 가지 보안 관련 취약점을 줄일 수 있습니다.

npm install helmet
const helmet = require("helmet");
app.use(helmet());

4. CORS 설정

CORS(Cross-Origin Resource Sharing)는 다른 출처의 리소스에 대한 접근을 제어하는 매커니즘으로, Node.js에서 CORS를 설정하려면 cors 패키지를 사용할 수 있습니다.

npm install cors
const cors = require("cors");

app.use(
  cors({
    origin: "https://thinky.tistory.com/", // 허용할 도메인
    methods: ["GET", "POST"],
  })
);

5.전체 코드

const express = require("express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
const dotenv = require("dotenv");
const helmet = require("helmet");
const cors = require("cors");

dotenv.config();

const app = express();
app.use(express.json());
app.use(helmet());
app.use(cors());

const users = []; // 사용자 정보를 저장할 배열

// 사용자 등록
app.post("/register", async (req, res) => {
  try {
    const { username, password } = req.body;

    if (!username || !password) {
      return res.status(400).send("Username and password are required");
    }

    const existingUser = users.find((user) => user.username === username);

    if (existingUser) {
      return res.statusCode(400).send("Username already exists");
    }

    const hashedPassword = await bcrypt.hash(password, 10);
    users.push({ username, password: hashedPassword });
    res.status(201).send("User registered");
  } catch (error) {
    console.error(error);
    res.status(500).send("Internal Server Error");
  }
});

// 사용자 조회
app.get("/users", (req, res) => {
  const userList = users.map((user) => ({ username: user.username }));
  res.json(userList);
});

// 사용자 로그인
app.post("/login", async (req, res) => {
  try {
    const { username, password } = req.body;
    const user = users.find((u) => u.username === username);
    if (!user) return res.status(400).send("User not found");

    const isValid = await bcrypt.compare(password, user.password);
    if (!isValid) return res.status(403).send("invalid password");

    const token = jwt.sign(
      { username: user.username },
      process.env.JWT_SECRET,
      {
        expiresIn: "1h",
      }
    );
    res.json({ token });
  } catch (error) {
    console.error(error);
    res.status(500).send("Internal Server Error");
  }
});

// 인증 미들웨어
const authenticateJWT = (req, res, next) => {
  const token = req.headers["authorization"]?.split(" ")[1];
  if (!token) return res.sendStatus(403);

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};

// 인증된 라우트
app.get("/dashboard", authenticateJWT, (req, res) => {
  res.send(`Welcome ${req.user.username}`);
});

// 서버 시작
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

 

.env 파일을 생성하고 JWT 비밀 키를 설정합니다.

JWT_SECRET=your_jwt_secret_key

 

서버를 실행하고 Postman에서 요청을 보냅니다. Postman에서 아래 url로 POST로 Send를 누르고 다음 설정으로 들어가 아래 데이터를 입력후 다시 Send를 눌러줍니다.

  • 사용자 등록 요청:
    • HTTP 메서드: POST
    • URL: http://localhost:5000/register
    • Body 설정:
      • raw 선택
      • JSON 형식으로 설정
      • 아래와 같은 데이터 입력:
{
    "username": "testuser",
    "password": "testpassword"
}
  • 사용자 조회 요청
    • HTTP 메서드: GET
    • URL: http://localhost:5000/users
  • 요청 및 응답 확인
    • 등록 후 응답 메시지 "User registered" 인지 확인합니다.
    • 조회 후 응답이 JSON 형식으로 사용자 목록인지 확인

 

GitHub - nodeJsroom/node-js-bloging

Contribute to nodeJsroom/node-js-bloging development by creating an account on GitHub.

github.com

 

LIST