1. Session과 JWT 개념
- Session과 JWT(JSON Web Token)은 모두 사용자 인증 및 식별에 사용되는 기술입니다.
- 세션은 사용자가 로그인하면 서버에서 세션을 생성하고 사용자의 상태 정보를 서버에 저장합니다. 클라이언트는 서버에 저장된 세션 정보를 통해 인증을 유지합니다
- JWT는 사용자가 로그인하면 서버는 JWT를 발급하고 클라이언트에게 전달합니다. 클라이언트는 이 JWT를 갖고 서버에 요청을 보내며, 서버는 JWT를 검증하여 사용자를 인증합니다.
- 세션은 서버에 상태를 유지하므로 서버 부하가 발생할 수 있고, 세션을 사용하려면 서버가 중앙 집중식으로 상태를 관리해야 하는 점을 고려해야 합니다.
- JWT는 토큰이 탈취될 경우 보안에 취약할 수 있습니다. 또한, 토큰의 크기가 크고, 한 번 발급되면 변경이 불가능하므로 만료 기간을 적절히 설정해야 합니다.
2. Session 구현
- 우선 app.js를 아래와 같이 수정하여 express-session 모듈을 추가해줍니다.
const express = require("express");
const session = require("express-session");
const app = express();
const port = process.env.PORT || 3000;
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
session({
secret: "1q2w3e4r!",
resave: false,
saveUninitialized: true,
})
);
app.use("/customer-api", require("./api/customers/customerController"));
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
- 그리고 컨트롤러 부분에 아래와 같이 로그인 기능을 구현합니다.
- 일반적으로는 ID와 Password를 이용해 로그인 기능을 구현하지만, 현재 DB에는 해당 정보가 없기 때문에 e-mail을 통한 로그인 방식으로 구현합니다.
router.post("/v1/login", async (req, res) => {
const email = req.body.email;
const customer = await customerService.getCustomerByEmail(email);
if (!customer) {
res.status(404).send();
} else {
req.session.email = req.body.email;
res.json(customer);
}
});
- 위에 코드에서 사용된 getCustomerByEmail는 아래와 같이 구현합니다.
const getCustomerByEmail = async (email) => {
try {
const customer = await Customer.findOne({ where: { email: email } });
return customer;
} catch (error) {
throw new Error("Error getting customer by email:", error);
}
};
- 위의 과정을 통해 로그인을 진행하게 되면 서버에 세션정보를 저장하게 됩니다.
- 이제 해당 세션을 통해 인증하는 과정을 구현해보겠습니다. lib 디렉토리에 session.js를 생성하고 아래와 같이 작성해 줍니다.
const isAuthenticated = (req, res, next) => {
if (req.session && req.session.email) {
return next();
} else {
res.status(401).send();
}
};
module.exports = {
isAuthenticated,
};
- 그리고 컨트롤러에서 인증이 필요한 라우터에 해당 미들웨어를 추가해줍니다.
/** 모든 고객 정보 가져오기 */
router.get("/v1/customer", isAuthenticated, async (req, res) => {
try {
const customers = await customerService.getAllCustomers();
res.json(customers);
} catch (error) {
console.error(error);
res.status(500).json({ error: "Internal Server Error" });
}
});
/** 특정 고객 정보 가져오기 */
router.get("/v1/customer/:customerId", isAuthenticated, async (req, res) => {
const customerId = Number(req.params.customerId);
const customer = await customerService.getCustomerById(customerId);
if (!customer) {
res.status(404).send();
}
res.json(customer);
});
- 해당 서버에 로그인 정보 없이 고객정보에 접근하려고 하면 401에러가 발생합니다.

- 없는 메일으로 로그인하면 404에러가 발생하고

- 존재하는 메일로 로그인 한 후

- 고객정보에 접근하면, 정상적으로 조회할 수 있습니다.
- 해당 기능을 고도화한다면, 타인의 정보는 접근 할 수 없고 본인 정보에만 접근 할 수 있게끔 수정 할 수도 있겠습니다.

- 참고로 postman에서 send아래 있는 cookies버튼을 눌러, 통신하고 있는 도메인을 추가해야 정상적인 테스트가 가능합니다.

3. JWT 구현
- lib디렉토리에 jwt.js파일을 생성하고 아래와 같이 작성합니다.
const jwt = require("jsonwebtoken");
const secretKey = "1q2w3e4r!";
function generateToken(payload) {
return jwt.sign(payload, secretKey, { expiresIn: "1h" });
}
function authenticateToken(req, res, next) {
const token = req.headers["authorization"];
if (!token) {
return res.status(403).json({ error: "Forbidden(Token)." });
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return res.status(401).json({ error: "Unauthorized(Token)." });
}
req.user = decoded;
next();
});
}
module.exports = {
generateToken,
authenticateToken,
};
- 그리고 컨트롤러 부분에 아래와 같이 로그인 기능을 구현합니다.
- 토큰을 생성하여 reponse합니다. front-end에서는 해당 토큰을 이용해 인증을 진행합니다.
router.post("/v1/login", async (req, res) => {
const email = req.body.email;
const customer = await customerService.getCustomerByEmail(email);
if (!customer) {
res.status(404).send();
} else {
const token = jwt.generateToken({
email: email,
});
res.status(200).json({ token: token });
}
});
- 위와 동일하게, 인증이 필요한 라우터에 미들웨어를 추가해줍니다.
/** 모든 고객 정보 가져오기 */
router.get("/v1/customer", jwt.authenticateToken, async (req, res) => {
const customers = await customerService.getAllCustomers();
res.json(customers);
});
/** 특정 고객 정보 가져오기 */
router.get("/v1/customer/:customerId", jwt.authenticateToken, async (req, res) => {
const customerId = Number(req.params.customerId);
const customer = await customerService.getCustomerById(customerId);
if (!customer) {
res.status(404).send();
}
res.json(customer);
});
- 토큰 없이 접근하면, 아래와 같이 401 에러가 발생합니다.

- 로그인을 통해 토큰을 획득하고

- 헤더에 토큰을 추가한뒤에 API에 접근하면 정상적으로 데이터를 확인 할 수 있습니다.

'ExpressJS' 카테고리의 다른 글
Chapter4 - Redis (0) | 2023.11.20 |
---|---|
Chapter3 - DB연결 (0) | 2023.09.19 |
Chapter2 - 프로젝트 구조 (0) | 2023.09.17 |
Chapter1. 프로젝트 생성 (0) | 2023.09.01 |