24.08.22 Day32

최지원·2024년 8월 22일

연락처 삭제하기

  • 메인 js
// 관련파일
// ./routes/contactRoutes-5.js
// ./controllers/contactController-15.js
// ./views/index-4.ejs
// ./views/add-2.ejs

const express = require("express");
const dbConnect = require("./config/dbConnect");
const methodOverride = require("method-override");

const app = express();

// 뷰 엔진 설정하기
app.set("view engine", "ejs");
app.set("views", "./views");

const port = 3000;

// public파일
app.use(express.static("./public"))
// method-override 미들웨어 등록
app.use(methodOverride("_method"))

dbConnect();

app.use(express.json());
app.use(express.urlencoded({extended:true}));

app.use("/contacts", require("./routes/contactRoutes")); // contactRoutes-3.js

app.listen(port,()=>{
    console.log("3000번 포트에서 서버 실행중...");
});
  • index-4.js 파일
<%- include('./include/_header-1') %>

 <!-- Main -->
   <main id="site-main">
    <div class="button-box">
        <a href="#" class="btn btn-light"><i class="fa-solid fa-user-plus"></i>연락처 추가</a>
    </div>
    <table class="table">
        <head>
            <tr>
                <th>이름</th>
                <th>메일주소</th>
                <th>전화번호</th>
                <th>&nbsp;</th>
            </tr>
        </head>
        <tbody> 
            <% contacts.forEach(contact => { %> 
            <tr>
                <td><%= contact.name %></td>
                <td><%= contact.email %></td>
                <td><%= contact.phone %></td>
                <td>
                    <!-- a 태그는 GET 방식의 호출 -->
                    <a href="/contacts/<%= contact._id %>" class="btn update" title="수정">
                        <i class="fas fa-pencil-alt"></i>
                    </a>

                    <form action="/contacts/<%= contact._id %>?_method=DELETE"method="POST"
                        style="display:inline;">
                        <input type="submit" class="btn delete" title="삭제" value="X">
                    </form>
                </td>
            </tr>
            <% }); %>
        </tbody>
    </table>
   </main>
  <!-- /Main -->

<%- include('./include/_footer') %>
  • add-2.js 파일
<!-- include header -->
<%- include('./include/_header-1') %>
    <!-- /include header -->

    <!-- Main -->
    <main id="site-main">
        <div class="button-box">
            <a href="/contacts" class="btn btn-light"><i class="fa-solid fa-list"></i>연락처 목록</a>
        </div>
        </div>
        <h2>연락처 추가</h2>
        <p>연락처 정보를 추가합니다.</p>
        <!-- POST localhost:3000/contacts/add -->
        <form action="/contacts/add" method="POST" id="add-user">
            <form method="POST" id="add-user">
                <div class="user-info">
                    <div class="col-12">
                        <label for="name" class="col-form-label">이름(Full Name)</label>
                        <div>
                            <input type="text" class="form-control" name="name" id="name" placeholder="홍길동">
                        </div>
                    </div>
                    <div class="col-12">
                        <label for="email" class="col-form-label">메일 주소(E-mail)</label>
                        <div>
                            <!-- name 속성의 키값에 따라서 서버의 파라미터 값을 전달한다! 중요 -->
                            <input type="text" class="form-control" name="email" id="email" placeholder="hong@abc.def">
                        </div>
                    </div>
                    <div class="col-12">
                        <label for="phone" class="col-form-label">전화번호(Mobile)</label>
                        <div>
                            <input type="text" class="form-control" name="phone" id="phone" placeholder="123-4567-8901">
                        </div>
                    </div>
                    <button type="submit">저장하기</button>
                </div>
            </form>
        </form>
    </main>
    <!-- /Main -->

    <%- include('./include/_footer') %>
  • contactController-15.js
const asyncHandler = require("express-async-handler");
const Contact = require("../models/contactModel");

// @desc 전체 연락처 가져오기
// @route GET /contacts
const getAllContacts = asyncHandler(async (req,res)=>{
    const contacts = await Contact.find();
    // 헤더와 푸터를 나눈 index-3.ejs
    res.render("index-4",{contacts : contacts});
});

// @desc 연락처 추가 폼
// @route GET /add
const addContactForm = (req,res) => {
    res.render("add-2");
};

// @desc 새 연락처 추가하기
// @route POST /contacts
const createContact = asyncHandler(async (req,res)=>{
    // 객체 구조분해할당, key와 value가 동일함
    const {name, email, phone} = req.body;
    if( !name || !email || !phone ){
        return res.status(400).send("필수값이 입력되지 않음");
    }
    const contact = await Contact.create({
        name,
        email,
        phone
    });
    // 새 연락처 추가 후에 리스트 화면으로 이동
    res.redirect("/contacts");
});

// @desc 연락처 상세보기 => 업데이트 화면으로 상세보기
// @route GET /contacts/:id
const getContact = asyncHandler(async(req,res)=>{
    const contact = await Contact.findById(req.params.id);
    res.render("update-3",{contact:contact}); // PUT방식 요청하기
});

// @desc 연락처 수정하기
// @route PUT /contacts/:id
const updateContact = asyncHandler(async(req,res)=>{
    const id = req.params.id;
    const { name, email, phone } = req.body;
    const updateContact = await Contact.findByIdAndUpdate(
        id,
        {name, email, phone},
        {new : true} // 수정한 후의 도큐먼트로 반환해 주는 옵션
    );
    res.redirect("/contacts");
});

// @desc 연락처 삭제하기
// @route DELETE /contacts/:id
const deleteContact = asyncHandler(async(req,res)=>{
    const id = req.params.id;
    await Contact.findByIdAndDelete(id);
    res.redirect("/contacts");
});

module.exports = {
    getAllContacts,
    createContact,
    getContact,
    updateContact,
    deleteContact,
    addContactForm
};

삭제 전 연락처 목록

삭제 후 결과

로그인 테스트하기

  • 메인 js
// 관리자 등록하기
// 로그인 화면구성

// 로그인 관련 파일
// ./routes/loginRoutes-2.js
// ./controllers/loginController-2.js
// ./views/home-2.ejs

// 관련 파일(그대로)
// ./routes/contactRoutes-5.js
// ./controllers/contactController-15.js
// ./views/index-4.ejs
// ./views/add-2.ejs
// ./views/update-3.ejs

const express = require("express");
const dbConnect = require("./config/dbConnect");
const methodOverride = require("method-override");

const app = express();

// 뷰 엔진 설정하기
app.set("view engine", "ejs");
app.set("views", "./views");

const port = 3000;

// public 폴더
app.use(express.static("./public"));
// method-override 미들웨어 등록
app.use(methodOverride("_method"));

dbConnect();

app.use(express.json());
app.use(express.urlencoded({extended:true}));

app.use("/", require("./routes/loginRoutes"));
app.use("/contacts", require("./routes/contactRoutes"));

app.listen(port,()=>{
    console.log("3000번 포트에서 서버 실행중...");
});
  • loginRoutes-2.js
const express = require("express");
const router = express.Router();
const { getLogin,loginUser } = require("../controllers/loginController-2");

// getLogin : 로그인폼 렌저
// loginUser : 로그인 처리(액션)
router.route("/").get(getLogin).post(loginUser);

module.exports = router;
  • home-2.ejs
<!-- include header -->
<%- include('./include/_home_header') %>
<!-- /include header -->

<!-- Main -->
<main id="site-main">

    <div class="home-container">
      <h3 style="margin-left: 80px;">로그인</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>
<!-- /Main -->

<!-- include footer-->
<%- include('./include/_footer') %>
<!-- /include footer -->
  • loginController-2.js
    로그인 데이터 입력
const asyncHandler = require("express-async-handler");

// @desc 로그인폼(화면)
// @route GET / 
const getLogin = (req,res) => {
    res.render("home-2");
};

// @desc 로그인 처리(액션)
// @route POST/
const loginUser = asyncHandler(async(req,res) => {
    // 로그인 처리를 위해서는 아이디/암호를 로그인 폼으로부터 받아온다.
    const{ username, password } = req.body;
    if (username === "admin" && password === "1234"){
        res.send("로그인 성공!");
    }else{
        res.send("로그인 실패!");
    }
});

module.exports = { getLogin, loginUser };

로그인 시도

로그인 성공

없는 정보로 로그인하여 로그인 실패

사용자 정보 DB 등록

  • 암호(비밀번호)를 암호화하여 DB에 저장
  • BCrypt 모듈을 사용하여 사용자 정보를 암호화(해시함수)하여 DB에 저장
  • 해시 : 특정 키워드(문자열)을 통해 암호화하는 방법, 단방향이다.(원문을 알 수 없다.)
  • npm i bcrypt 설치

  • 메인 js
/*
로그인 관련 파일
./routes/loginRoutes-4.js
./controllers/loginController-4.js
./views/home-2.ejs
./views/register-1.ejs

관련 파일(그대로)
./routes/contactRoutes-5.js
./controllers/contactController-15.js
./views/index-4.ejs
./views/add-2.ejs
./views/update-3.ejs
*/

const express = require("express");
const dbConnect = require("./config/dbConnect");
const methodOverride = require("method-override");

const app = express();

// 뷰 엔진 설정하기
app.set("view engine", "ejs");
app.set("views", "./views");

const port = 3000;

// public 폴더
app.use(express.static("./public"));
// method-override 미들웨어 등록
app.use(methodOverride("_method"));

dbConnect();

app.use(express.json());
app.use(express.urlencoded({extended:true}));

app.use("/", require("./routes/loginRoutes"));
app.use("/contacts", require("./routes/contactRoutes"));

app.listen(port,()=>{
    console.log("3000번 포트에서 서버 실행중...");
});
  • loginRoutes-4.js
const express = require("express");
const router = express.Router();
const {
    getLogin,
    loginUser,
    getRegister,
    registerUser
} = require("../controllers/loginController-4");

// getLogin : 로그인폼 렌저
// loginUser : 로그인 처리(액션)
router.route("/").get(getLogin).post(loginUser);

// getRegister : 사용자 등록폼
// registerUser : 사용자등록 처리(액션)
router.route("/register").get(getRegister).post(registerUser);

module.exports = router;
  • loginController-4.js
const asyncHandler = require("express-async-handler");
const bcrypt = require("bcrypt");

// @desc 로그인폼(화면)
// @route GET / 
const getLogin = (req,res) => {
    res.render("home-2");
};

// @desc 로그인 처리(액션)
// @route POST/
const loginUser = asyncHandler(async(req,res) => {
    // 로그인 처리를 위해서는 아이디/암호를 로그인 폼으로부터 받아온다.
    const{ username, password } = req.body;
    if (username === "admin" && password === "1234"){
        res.send("로그인 성공!");
    }else{
        res.send("로그인 실패!");
    }
});

// @desc 사용자 등록폼
// @route GET /register
const getRegister = (req,res) => {
    res.render("register-1");
};

// @desc 사용자등록 처리(액션)
// @route POST /register
const registerUser = asyncHandler(async(req,res) => {
    const{ username, password, password2 } = req.body;
    if(!username || !password){
        res.send("필수값이 없습니다.");
        return;
    }
    if(password===password2){
        //사용자가 입력한 암호("1234")를 해시암호화 한다.
        // 10 : 해시함수를 10번 수행
        const hashedPassword = await bcrypt.hash(password, 10);
        console.log(password);
        console.log(hashedPassword);
      	res.send("사용자 등록되었습니다.")
    }else{
        res.send("비밀번호와 비밀번호2가 다릅니다.");
    }
});

module.exports = { getLogin, loginUser, getRegister, registerUser };
  • register-1.ejs 파일
<!-- include header -->
<%- include('./include/_home_header') %>
<!-- /include header -->

  <!-- Main -->
  <main id="site-main">

    <form action="/register" method="POST" class="register">
      <h3>사용자 등록</h3>

      <label for="username"><b>아이디</b></label>
      <input type="text" placeholder="아이디" name="username" id="username">
      <label for="password"><b>비밀번호</b></label>
      <input type="password" placeholder="비밀번호" name="password" id="password">
      <label for="password2"><b>비밀번호 확인</b></label>
      <input type="password" placeholder="비밀번호 확인" name="password2" id="password2">

      <input type="submit" value="등록" class="register-btn">
    </form>    
  </main>
  <!-- /Main -->

<!-- include footer -->
<%- include('./include/_footer') %>
<!-- /include footer -->

데이터 입력

데이터 입력 후 결과

웹 애플리케이션 사용자 인증

  • 쿠키 : 클라이언트(PC,Mobile)에 저장되는 임시데이터
  • 세션 : 서버에 저장되는 데이터(DB, 메모리)
  • 토큰 : 클라이언트와 서버에 저장되는 암호된 데이터
  • 쿠키파서, JWT 미들웨어 설치 : npm i cookie-parser jsonwebtoken

쿠키 생성/삭제

const express = require("express");
const cookieParser = require("cookie-parser");

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

app.get("/",(req,res)=> {
    // HTTP 응답 헤더 : setCookie : 값을 넣어서 응답하면, 클라가 쿠키 저장
    // httpOnly : HTTP통신을 통해서만 쿠키를 생성하도록 설정. JS 통해서 쿠키 생성을 막음.
    res.cookie("Kim","1234",{httpOnly:true});
    res.send("쿠키 생성");
});

app.listen(5000, ()=>{
    console.log("5000번 포트에서 서버 실행 중...");
});

사용자 인증 - 세션처리

  • 세션관리 : 미들웨어
  • npm i express-session connect-mongo 설치
const express = require("express");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const MongoStore = require("connect-mongo");
require("dotenv").config();

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

// 미들웨어 express-session 등록
app.use(
    session({
        name : "connect.sid",
        secret : "secret code",
        resave : false,
        saveUninitialized : true,
        store : MongoStore.create({mongoUrl:process.env.DB_CONNECT}),
        cookie : { maxAge:60 * 60 * 24 * 1000 }
    })
);

app.get("/",(req,res)=> {
    if(req.session.count){ // 클라에 세션정보가 있으면(재방문 시)
        req.session.count++;
        res.write("<p>count:"+req.session.count+"</p>");
        res.end();
    }else{ // 첫 방문 시
        req.session.count = 1;
        res.send("첫 번째 방문입니다.");
    }
});

app.get("/session",(req,res) => {
    console.log(req.session);
    res.send("세션 정보 조회");
});

app.get("/delete-session",(req,res)=> {
    req.session.destroy((err)=>{
        if(err){
            console.log(err);
        }else{
            res.clearCookie("connect.sid");
            res.send("세션 삭제");
        }
    })
});

app.listen(5000, ()=> {
    console.log("5000번 포트에서 서버 실행 중...");
});

세번째 방문했을 경우 - 방문의 연속성 확보

사용자 인증 - JWT 토근 생성

  • 메인 js
/*
로그인 관련 파일
./routes/loginRoutes-5.js
./controllers/loginController-5.js
./views/home-2.ejs
./views/register-1.ejs

관련 파일(그대로)
./routes/contactRoutes-5.js
./controllers/contactController-15.js
./views/index-4.ejs
./views/add-2.ejs
./views/update-3.ejs
./.env JWT_SECRET = 12345 new
*/

const express = require("express");
const dbConnect = require("./config/dbConnect");
const methodOverride = require("method-override");

const app = express();

// 뷰 엔진 설정하기
app.set("view engine", "ejs");
app.set("views", "./views");

const port = 3000;

// public 폴더
app.use(express.static("./public"));
// method-override 미들웨어 등록
app.use(methodOverride("_method"));

dbConnect();

app.use(express.json());
app.use(express.urlencoded({extended:true}));

app.use("/", require("./routes/loginRoutes"));
app.use("/contacts", require("./routes/contactRoutes"));

app.listen(port,()=>{
    console.log("3000번 포트에서 서버 실행중...");
});
  • loginRoutes-5.js
const express = require("express");
const router = express.Router();
const { 
    getLogin, 
    loginUser,
    getRegister,
    registerUser
} = require("../controllers/loginController-5");

//getLogin : 로그인폼 렌더
//loginUser : 로그인 처리(액션)
router.route("/").get(getLogin).post(loginUser);
//getRegister : 사용자등록폼 렌더
//registerUser : 사용자등록 처리(액션)
router.route("/register").get(getRegister).post(registerUser);

module.exports = router;
  • loginController-5.js
const asyncHandler = require("express-async-handler");
const bcrypt = require("bcrypt");
const User = require("../models/userModel");
require("dotenv").config();
const jwt = require("jsonwebtoken");
const jwtSecret = process.env.JWT_SECRET;

// @desc 로그인폼(화면)
// @route GET /
const getLogin = (req, res) => {
    res.render("home-2");
};

// @desc 로그인 처리(액션)
// @route POST /
const loginUser = asyncHandler(async (req,res) =>{
    //로그인 처리를 위해서는 아이디/암호를 로그인폼으로부터 받아온다.
    const { username, password } = req.body;

    // JWT토큰기반의 로그인 인증처리
    const user = await User.findOne({username});
    if(!user){
        return res.status(401).json({message:"일치하는 사용자가 없습니다."});
    }
    // DB의 사용자정보와 입력된 사용자정보가 일치하는지 확인
    const isMatch = await bcrypt.compare(password, user.password);
    if(!isMatch){
        return res.status(401).json({message:"비밀번호가 일치하지 않습니다."});
    }
    // 사용자 토큐먼트 id(랜덤생성)를 기반으로 토큰데이터 생성(발행)해줌.
    const token = jwt.sign({id : user._id}, jwtSecret);
    res.cookie("tooken",token,{httpOnly:true});
    res.redirect("/contacts"); //로그인된 사용자만 연락처 리스트화면으로 이동하도록 한다.
});

// @desc 사용자등록폼
// @route GET /register 
const getRegister = (req, res) => {
    res.render("register-1");
};

// @desc 사용자등록 처리(액션)
// @route POST /register
const registerUser = asyncHandler(async (req, res) => {
    const { username, password, password2 } = req.body;
    if( !username || !password ){
        res.send("필수값이 없습니다.");
        return;
    }
    if( password === password2 ) {
        //사용자가 입력한 암호("1234")를 해시암호화 한다.
        //10 : 해시함수를 10번 수행한다.
        const hashedPassword = await bcrypt.hash(password, 10);
        console.log( password);        
        console.log( hashedPassword );
        const user = await User.create({ username, password: hashedPassword });
        res.status(201).json({message: "사용자 등록되었습니다.", user })
    }else{
        res.send("비번과 비번2가 틀립니다.");
    }
});

module.exports = { getLogin, loginUser, getRegister, registerUser };
  • .env파일
    JWT_SECRET = 12345 저장 후 npm start다시 시작


    기존에 저장된 아이디로 로그인

쿠키에 정보 저장 확인 가능

0개의 댓글