로그인 기능 구현
-login.js 추가
-header.js, mainHeader.js, registerHeader.js 로 헤더 3개 분류
-백엔드-
controllers - <loginController-2.js> : 로그인 기능
(...)
require("dotenv").config(); //.env 파일 불러오기
const jwt = require("jsonwebtoken"); //jsonwebtokeen 불러오기
const jwtSecret = process.env.JWT_SECRET; //비밀키 지정
(...)
//Post Login User, / : 로그인 기능
const loginUser = asynchHandler(async (req, res) => {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) {
return res.status(401).json({ message: "일치하는 사용자가 없습니다." });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: "비밀번호가 일치하지 않습니다." });
}
const token = jwt.sign({ id: user._id }, jwtSecret); //토큰 생성
res.cookie("token", token, { httpOnly: true }); //쿠키 생성
res.status(200).json({ message: "로그인 성공", token });
});
(...)
module.exports = { loginUser, registerUser }; //loginUser 내보내기
routes - <loginRoutes-2.js> : 로그인 라우터
const express = require("express");
const router = express.Router();
const { loginUser, registerUser } = require("../controllers/loginController-2");
router.route("/").post(loginUser); //로그인 라우터
router.route("/register").post(registerUser);
module.exports = router;
-프론트엔드-
index.js
App.js
component
-header.js
-mainHeader.js
-registerHeader.js
page
-main.js
-add.ejs
-update.js
-register.js
-login.js
css
-style.css
App.js
import React from "react";
import Main from "./page/main";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Add from "./page/add";
import Update from "./page/update";
import Register from "./page/register";
import Login from "./page/login";
function App() {
return (
<div>
<BrowserRouter>
<Routes>
<Route index element={<Login />} />
<Route path="/contact" element={<Main />} />
<Route path="/register" element={<Register />} />
<Route path="/add" element={<Add />} />
<Route path="/contact/:id" element={<Update />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
page - <login.js> : 로그인 페이지
※window.location.replace() : 페이지 이동 함수
import React, { useEffect, useState } from "react";
import Header from "../component/header";
import axios from "axios";
import { useNavigate } from "react-router-dom";
function Login() {
const navigate = useNavigate();
const [loginName, setLoginName] = useState("");
const [loginPassword, setLoginPassword] = useState("");
const changeLoginName = (e) => {
setLoginName(e.target.value);
};
const changeLoginPassword = (e) => {
setLoginPassword(e.target.value);
};
const loginForm = async (e) => {
e.preventDefault();
const loginData = { username: loginName, password: loginPassword };
if (loginName === "" || loginPassword === "") {
alert("ID, 비밀번호 입력을 해주세요.");
} else {
try {
const response = await axios.post("http://localhost:8080/", loginData); //POST 보내기
const { token } = response.data; //토큰 생성
localStorage.setItem("token", token); //토큰을 로컬 스토리지에 저장
navigate("/contact"); //메인 페이지로 이동
alert(response.data.message);
} catch (err) {
alert(err.response.data.message);
setLoginName("");
setLoginPassword("");
}
}
};
useEffect(() => {
if (localStorage.getItem("token") !== null) { //로컬 스토리지에 token이 있을 경우
alert("이미 로그인 중입니다.");
window.location.replace("http://localhost:3000/contact"); //contact 페이지로 이동
}
}, []);
return (
<div>
<Header />
<div className="site-main">
<h3>로그인</h3>
<p>로그인이 필요한 서비스입니다.</p>
<form onSubmit={loginForm} className="login">
<div>
<label>아이디</label>
<input
type="text"
value={loginName || ""}
onChange={changeLoginName}
/>
</div>
<div>
<label>비밀번호</label>
<input
type="password"
value={loginPassword || ""}
onChange={changeLoginPassword}
/>
</div>
<button type="submit" className="login-btn">
로그인
</button>
</form>
</div>
</div>
);
}
export default Login;
page - <main.js> : 메인 페이지
import React, { useEffect, useState } from "react";
import axios from "axios";
import "../css/style.css";
import { useNavigate } from "react-router-dom";
import MainHeader from "../component/mainHeader";
function Main() {
const navigate = useNavigate();
const [lists, setLists] = useState([]);
const deleteData = (deleteId) => {
alert("삭제되었습니다.");
axios.delete(`http://localhost:8080/contact/${deleteId}`);
window.location.replace("/contact");
};
useEffect(() => {
if (localStorage.getItem("token") == null) { //로컬 스토리지에 token이 없을 경우
alert("로그인 후 이용해주세요.");
window.location.replace("http://localhost:3000");
} else { //로컬 스토리지에 token이 있을 경우
axios
.get("http://localhost:8080/contact")
.then((res) => setLists(res.data));
}
}, []);
return (
<div>
<MainHeader />
<div className="site-main">
<div className="button-box">
<button onClick={() => navigate("/add")}>+ 연락처 추가</button>
</div>
<table className="table">
<thead>
<tr>
<th>이름</th>
<th>이메일</th>
<th>전화번호</th>
<th> </th>
</tr>
</thead>
<tbody>
{lists.map((list, index) => {
return (
<tr key={index}>
<td>{list.name}</td>
<td>{list.email}</td>
<td>{list.phone}</td>
<td>
<button onClick={() => navigate(`/contact/${list._id}`)}>
수정
</button>
<button onClick={() => deleteData(list._id)}>삭제</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
);
}
export default Main;
page - <add.js> : 연락처 추가 페이지
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";
import MainHeader from "../component/mainHeader";
function Add() {
const navigate = useNavigate();
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [phone, setPhone] = useState("");
const changeName = (e) => {
setName(e.target.value);
};
const changeEmail = (e) => {
setEmail(e.target.value);
};
const changePhone = (e) => {
setPhone(e.target.value);
};
const addForm = (e) => {
e.preventDefault();
const userData = { name: name, email: email, phone: phone };
if (name === "" || email === "" || phone === "") {
alert("입력해주세요.");
} else {
axios
.post("http://localhost:8080/contact/add", userData)
.then(() => navigate("/contact"))
.then(() => {
alert("저장되었습니다.");
});
}
};
useEffect(() => { //
if (localStorage.getItem("token") == null) { //로컬 스토리지에 token이 없을 경우
alert("로그인 후 이용해주세요.");
window.location.replace("http://localhost:3000");
}
}, []);
return (
<div>
<MainHeader />
<div className="site-main">
<div className="button-box">
<button onClick={() => navigate("/contact")}>연락처 목록</button>
</div>
<h2>연락처 추가</h2>
<p>연락처 정보를 추가합니다</p>
<form onSubmit={addForm}>
<div className="user-info">
<div>
<label>이름</label>
<input type="text" value={name || ""} onChange={changeName} />
</div>
<div>
<label>메일 주소</label>
<input type="text" value={email || ""} onChange={changeEmail} />
</div>
<div>
<label>전화번호</label>
<input type="text" value={phone || ""} onChange={changePhone} />
</div>
<button type="submit">저장하기</button>
</div>
</form>
</div>
</div>
);
}
export default Add;
page - <update.js> : 연락처 수정 페이지
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate, useParams } from "react-router-dom";
import MainHeader from "../component/mainHeader";
function Update() {
const { id } = useParams();
const navigate = useNavigate();
const [updateName, setModifyName] = useState("");
const [updateEmail, setModifyEmail] = useState("");
const [updatePhone, setModifyPhone] = useState("");
const changeModifyName = (e) => {
setModifyName(e.target.value);
};
const changeModifyEmail = (e) => {
setModifyEmail(e.target.value);
};
const changeModifyPhone = (e) => {
setModifyPhone(e.target.value);
};
const updateForm = (e) => {
e.preventDefault();
const updateUserData = {
name: updateName,
email: updateEmail,
phone: updatePhone,
};
if (updateName === "" || updateEmail === "" || updatePhone === "") {
alert("입력해주세요.");
} else {
axios
.put(`http://localhost:8080/contact/${id}`, updateUserData)
.then(() => navigate("/contact"))
.then(() => {
alert("수정되었습니다.");
});
}
};
useEffect(() => {
if (localStorage.getItem("token") == null) { //로컬 스토리지에 token이 없을 경우
alert("로그인 후 이용해주세요.");
window.location.replace("http://localhost:3000");
} else { //로컬 스토리지에 token이 있을 경우
axios.get(`http://localhost:8080/contact/${id}`).then((res) => {
setModifyName(res.data.name);
setModifyEmail(res.data.email);
setModifyPhone(res.data.phone);
});
}
}, [id]);
return (
<div>
<MainHeader />
<div className="site-main">
<div className="button-box">
<button onClick={() => navigate("/contact")}>연락처 목록</button>
</div>
<h2>연락처 수정</h2>
<p>연락처 정보를 수정합니다.</p>
<form onSubmit={updateForm}>
<div className="user-info">
<div>
<label>이름</label>
<input
type="text"
value={updateName || ""}
onChange={changeModifyName}
/>
</div>
<div>
<label>메일 주소</label>
<input
type="text"
value={updateEmail || ""}
onChange={changeModifyEmail}
/>
</div>
<div>
<label>전화번호</label>
<input
type="text"
value={updatePhone || ""}
onChange={changeModifyPhone}
/>
</div>
<button type="submit">수정하기</button>
</div>
</form>
</div>
</div>
);
}
export default Update;
component - <mainHeader.js> : 로그아웃 헤더
import React from "react";
import "../css/style.css";
import { useNavigate } from "react-router-dom";
function MainHeader() {
const navigate = useNavigate();
const goToLogin = () => {
localStorage.removeItem("token"); //로컬 스토리지에 token 제거
alert("로그아웃 되었습니다.");
navigate("/");
};
return (
<div>
<header className="border-shadow">
<div className="container">
<nav>
<p>My Contact</p>
</nav>
<div className="login-box">
<button onClick={goToLogin} className="logoutBth">
로그아웃
</button>
</div>
</div>
</header>
</div>
);
}
export default MainHeader;
'Do it Node.js > React BackEnd' 카테고리의 다른 글
5. 회원가입 페이지 (0) | 2024.03.19 |
---|---|
4. 연락처 수정 페이지, 삭제 (0) | 2024.03.17 |
3. 연락처 추가 페이지, react-router-dom (0) | 2024.03.15 |
2. 연락처 목록 페이지, Axios (0) | 2024.03.14 |
1. 백엔드 연결 (0) | 2024.03.14 |