쿠키 : 웹 브라우저를 이용할 때 사용자 컴퓨터에 저장되는 정보
-cookie-parser : 웹 애플리케이션에서 쿠키를 만들거나 구문을 분석할 떄 사용
>> npm install cookie-parser
세션 : 웹 브라우저를 이용할 때 서버에 저장되는 정보
캐시 : 데이터를 미리 복사해 놓는 임시 저장 장소
토큰
-세션과는 다르게 서버에 저장하지 않음
-사용자 정보, 위조를 막는 서명 등 인증에 필요한 모든 정보가 담김
-서버 간 공유할 수도 있음
JWT : 노드에서 자주 사용하는 JSON 형식의 토큰 방식 모듈, 헤더/페이로드/서명 3영역으로 나뉨
-헤더 : 알고리즘과 유형이 담김
-페이로드 : 사용자 인증 정보, 내용이 담김
-서명 : 비밀 키로 .env 파일같이 안전한 곳에 저장해서 사용
>> npm install jsonwebtoken
[로그인 페이지]
<%- include('./include/_home_header') %>
<main id="site-main">
<div class="home-container">
<h3>로그인</h3>
<p>로그인이 필요한 서비스입니다.</p>
<form action="/" method="POST" class="login">
<label for="username"><b>Username</b></label>
<input
type="text"
placeholder="사용자 아이디"
name="username"
id="username"
/>
<label for="password"><b>Password</b></label>
<input
type="password"
placeholder="비밀번호"
name="password"
id="password"
/>
<button type="submit">로그인</button>
</form>
</div>
</main>
<%- include('./include/_footer') %>
[토큰 생성]
<.env> : 토큰 비밀키를 지정
DB_CONNECT = mongodb+srv://<username>:<password>@cluster0.oimz7n5.mongodb.net/myContact
//커넥션 스트링(데이터베이스)를 변수에 지정
JWT_SECRET = '비밀키' // 토큰 비밀키 지정
controllers - <loginController.js> : 로그인 시 토큰 생성
※.findOne() : 조건에 맞는 도큐먼트가 여러 개일 경우 첫 번째 도큐번트를 찾는 함수
※bcrypt.compare(data, encrypted, callback) : 입력한 비밀번호와 저장된 비밀번호가 같은 지 비교하는 함수
-data : 입력값
-encrypted : 저장된 입력값
-callback : 콜백 함수
※jwt.sign(페이로드, 비밀키, [옵션, 콜백]) : 토큰을 생성하는 함수
※res.cookie(name, value, option) : 쿠키를 생성하는 함수
-httpOnly : true : HTTP 통신에서만 쿠키를 생성하도록 제한
(...)
require("dotenv").config; //.env 파일 불러오기
const jwt = require("jsonwebtoken"); //jsonwebtoken 불러오기
const jwtSecret = process.env.JWT_SECRET; //.env 파일에 비밀키 JWT_SECRET 지정
(...)
//Post Login User, /
const loginUser = asynchHandler(async (req, res) => {
const { username, password } = req.body;
const user = await User.findOne({ username }); //입력값이 DB에 username으로 있는 지 조회
if (!user) { //입력값이 DB에 username으로 없는 경우
return res.status(401).json({ message: "일치하는 사용자가 없습니다." });
}
const isMatch = await bcrypt.compare(password, user.password); //입력값과 DB에 저장된 비밀번호 비교
if (!isMatch) { //입력값이 DB에 비밀번호로 없는 경우
return res.status(401).json({ message: "비밀번호가 일치하지 않습니다." });
}
const token = jwt.sign({ id: user._id }, jwtSecret); //사용자 ID를 기반으로 JWT 토큰 생성
res.cookie("token", token, { httpOnly: true }); //생성된 토큰을 쿠키에 저장
res.redirect("/contact"); //로그인 성공 시 /contact로 이동
});
(...)
[로그인 여부 확인]
middlewares - <checkLogin.js> : 로그인 여부 확인 미들웨어
※"Cache-Control", "no-cache, no-store, must-revalidate"
-Cache-Control : 캐시 설정
-no-cache : 브라우저에서 캐시를 사용하지 않고 서버에서 응답을 매번 다시 받음
-no-store : 서버의 응답을 캐시에 저장하지 않음
-must-revalidate : 만일 캐시에 있는 정보를 사용하더라도 반드시 서버에 다시 확인해야 함
※jwt.verify(토큰, 비밀키, [옵션]) : 서버에서 토큰을 검증하고 해석하는 함수
const jwt = require("jsonwebtoken"); //jsonwebtoken 불러오기
require("dotenv").config; //.env 파일 불러오기
const jwtSecret = process.env.JWT_SECRET; //.env 파일에 비밀키 JWT_SECRET 지정
const checkLogin = async (req, res, next) => {
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); //브라우저 캐시를 막음
const token = req.cookies.token; //요청한 쿠키에서 토큰값 가져오기
if (!token) { //토큰이 없을 경우(로그인이 안 되있을 경우)
return res.redirect("/");
}
try { //토큰이 있을 경우(로그인을 했을 경우)
const decoded = jwt.verify(token, jwtSecret); //토큰 해석
req.username = decoded.username; //해석한 토큰을 사용자 이름에 저장
next();
} catch (error) {
return res.status(401).json({ message: "로그인이 필요합니다." });
}
};
module.exports = checkLogin;
routes - <contactRoutes.js> : checkLogin.js 미들웨어 등록
const express = require("express");
const router = express.Router();
const cookieParser = require("cookie-parser"); //cookie-parser 불러오기
const checkLogin = require("../middlewares/checkLogin"); //checkLogin 미들웨어 불러오기
const {
getAllContact,
createContect,
getContact,
updateContact,
deleteContact,
addContactForm,
} = require("../controllers/contactController");
router.use(cookieParser()); //cookie-parser 등록
router.route("/").get(checkLogin, getAllContact);
router.route("/add").get(checkLogin, addContactForm).post(checkLogin, createContect);
router.route("/:id").get(checkLogin, getContact).put(checkLogin, updateContact)
.delete(checkLogin, deleteContact);
module.exports = router;
[로그아웃]
views - include - <_header.ejs> : 로그아웃 추가
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>연락처 관리하기</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
/>
<link rel="stylesheet" href="/css/style.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
</head>
<body>
<header class="border-shadow">
<div class="container">
<nav>
<a href="/"><i class="fa-solid fa-address-book"></i> My Contacts</a>
</nav>
<div class="login-box">
<a href="/logout">로그아웃</a> <!--로그아웃-->
</div>
</div>
</header>
</body>
</html>
controllers - <loginController.js> : 로그아웃 추가
※res.clearCookie (name) : 쿠키 삭제
(...)
//Get Logout, /logout : 로그아웃
const logout = (req, res) => {
res.clearCookie("token"); //쿠키에 있는 토큰 삭제
res.redirect("/");
};
module.exports = { getLogin, loginUser, getRegister, registerUser, logout }; //logout 내보냄
routes - <loginRoutes.js> : 로그아웃 기능 라우팅
const express = require("express");
const router = express.Router();
const {
getLogin,
loginUser,
getRegister,
registerUser,
logout,
} = require("../controllers/loginController");
router.route("/").get(getLogin).post(loginUser); //로그인 페이지
router.route("/register").get(getRegister).post(registerUser);
router.route("/logout").get(logout); //로그아웃 기능
module.exports = router;
'Do it Node.js > EJS BackEnd' 카테고리의 다른 글
19. 회원가입, bcrypt (0) | 2024.03.19 |
---|---|
18. 연락처 추가, 삭제 (0) | 2024.03.16 |
17. 연락처 추가 (0) | 2024.03.15 |
16. include, 연락처 표시 (0) | 2024.03.14 |
15. EJS (0) | 2024.03.13 |