<step94>'react-고객관리 사이트(로그인 구현_COOKIE)'
2022.07.18 - [공부가 좋아서] - 'redux(react)_고객관리 사이트_redux로 구현'
<step82>'redux(react)_고객관리 사이트_redux로 구현'
2022.07.08 - [공부가 좋아서] - 'react_고객관리 사이트 구현_step_final' 'react_고객관리 사이트 구현_step_final'" data-og-description="1) green_customer_client components/ CreateCustomer.js import Rea..
zoaseo.tistory.com
1)

2)
서버구현
1. join 경로 post 요청시
customer_members 테이블에 데이터 추가하기
비밀번호는 암호화하여 저장
등록일은 Now()함수를 사용해서 현재 날짜를 저장
패스워드 암호화 알고리즘 라이브러리 - bcrypt 설치
npm install bcrypt
3)
https://www.npmjs.com/package/bcrypt
bcrypt
A bcrypt library for NodeJS.. Latest version: 5.0.1, last published: a year ago. Start using bcrypt in your project by running `npm i bcrypt`. There are 3418 other projects in the npm registry using bcrypt.
www.npmjs.com

4)
sever 구현
const express = require("express");
const cors = require("cors");
const app = express();
const port = 3001;
const mysql = require("mysql");
const fs = require("fs");
const bcrypt = require('bcrypt');
const saltRounds = 10;
const dbinfo = fs.readFileSync('./database.json');
// 받아온 json데이터를 객체형태로 변경 JSON.parse
const conf = JSON.parse(dbinfo);
// connection mysql연결 createConnection()
// connection.connect() 연결하기
// connection.end() 연결종료
// connection.query('쿼리문', callback함수)
// callback(error, result, result의 field정보)
const connection = mysql.createConnection({
host: conf.host,
user: conf.user,
password: conf.password,
port: conf.port,
database: conf.database,
})
// 회원가입 요청
app.post("/join", async (req, res)=>{
// green1234
let myPlaintextPass = req.body.userpass;
let myPass = "";
if(myPlaintextPass != '' && myPlaintextPass != undefined){
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPass, salt, function(err, hash) {
// Store hash in your password DB.
myPass = hash;
console.log(myPass);
});
});
}
})


// 회원가입 요청
app.post("/join", async (req, res)=>{
// green1234
let myPlaintextPass = req.body.userpass;
let myPass = "";
if(myPlaintextPass != '' && myPlaintextPass != undefined){
bcrypt.genSalt(saltRounds, function(err, salt) {
bcrypt.hash(myPlaintextPass, salt, function(err, hash) {
// Store hash in your password DB.
myPass = hash;
console.log(myPass);
// 쿼리 작성
const {username, userphone, userorg, usermail} = req.body;
connection.query("insert into customer_members(username, userpass, userphone, userorg, usermail, regdate) values(?,?,?,?,?,DATE_FORMAT(now(),'%Y-%m-%d'))",
[username, myPass, userphone, userorg, usermail],
(err, result, fields) => {
console.log(result)
console.log(err)
res.send("등록되었습니다.")
}
)
});
});
}
})


5)
login 경로 post 요청시
usermail 값으로 일치하는 데이터를 조회(select)
입력받은 userpass를 암호화하여 조회한 데이터의 암호화된 값과
비교하여 일치하는지 확인
일치하면 조회한 데이터를 응답해줌
client 구현
components/Header.js
import React from 'react';
import { Link } from 'react-router-dom';
const Header = () => {
return (
<div id="header">
<h1>그린고객센터</h1>
<ul>
<li><Link to="/">고객리스트보기</Link></li>
<li><Link to="/write">신규 고객 등록하기</Link></li>
<li><Link to="/login">로그인</Link></li>
<li><Link to="/join">회원가입</Link></li>
<li>고객 검색</li>
</ul>
</div>
);
};
export default Header;
components/JoinForm.js
import React, { useState } from 'react';
import { Table, TableBody, TableRow, TableCell } from '@mui/material';
import axios from 'axios';
import { API_URL } from '../config/conf';
import { useNavigate } from 'react-router-dom';
const JoinForm = () => {
const navigate = useNavigate();
const [formData, setFormData ] = useState({
username: "",
userpass: "",
userpassck: "",
userphone: "",
userorg: "",
usermail: ""
})
const onChange = (e) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]:value
})
}
// 폼 submit 이벤트
const onSubmit = (e) => {
// form에 원래 연결된 이벤트를 제거
e.preventDefault();
console.log(formData);
// 전화번호가 숫자인지 체크하기
if(isNaN(formData.userphone)){
alert("전화번호는 숫자만 입력해주세요");
setFormData({
...formData,
userphone: "",
})
}
// input에 값이 있는지 체크하고
// 입력이 다되어있으면 post전송
else if(formData.username !== "" && formData.userpass !== "" &&
formData.userphone !== "" && formData.userpassck !== "" &&
formData.userorg !== "" && formData.usermail !== ""){
addMember();
}
}
function addMember() {
axios.post(`${API_URL}/join`,formData)
.then(res=>{
alert('등록되었습니다.');
navigate('/');
})
.catch(e=>{
console.log(e);
})
}
return (
<div>
<h2>신규고객등록하기</h2>
<form onSubmit={onSubmit}>
<Table>
<TableBody>
<TableRow>
<TableCell>이름</TableCell>
<TableCell>
<input name="username" type="text"
value={formData.username}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>비밀번호</TableCell>
<TableCell>
<input name="userpass" type="text"
value={formData.userpass}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>비밀번호 체크</TableCell>
<TableCell>
<input name="userpassck" type="text"
value={formData.userpassck}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>연락처</TableCell>
<TableCell>
<input name="userphone" type="text"
value={formData.userphone}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>이메일</TableCell>
<TableCell>
<input name="usermail" type="text"
value={formData.usermail}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell>소속</TableCell>
<TableCell>
<input name="userorg" type="text"
value={formData.userorg}
onChange={onChange}/>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={2}>
<button type="submit">등록</button>
<button type="reset">취소</button>
</TableCell>
</TableRow>
</TableBody>
</Table>
</form>
</div>
);
};
export default JoinForm;

server
// 로그인 요청
app.post('/login', async (req, res)=> {
// usermail 값에 일치하는 데이터가 있는지 select문
// userpass 암호화해서 쿼리 결과의 패스워드랑 일치하는지를 체크
const { usermail, userpass } = req.body;
connection.query(`select * from customer_members where usermail = '${usermail}'`,
(err, rows, fields)=>{
if(rows != undefined){
if(rows[0] == undefined){
res.send(null)
}else {
// Load hash from your password DB.
bcrypt.compare(userpass, rows[0].userpass, function(err, result) {
// result == true
if(result == true){
res.send(rows[0])
}else {
res.send("실패")
}
});
}
}else {
res.send(null)
}
}
)
})
1. 로그인 리듀서 작성
modules/logincheck.js
// 리덕스 액션타입, 액션 생성 함수, 초기값, 리듀서
const SET_LOGIN = 'SET_LOGIN';
const SET_LOGOUT = 'SET_LOGOUT';
// 액션 생성함수
export const setLogin = () => ({
type: SET_LOGIN
})
export const setLogout = () => ({
type: SET_LOGOUT
})
// 초기값 설정
const initialState = {
isLogin: false
}
// 홈으로 이동함수
export const goToHome = (navigate) => () => {
navigate('/');
}
// 리듀서 만들기
export default function logincheck(state=initialState, action){
switch(action.type){
case SET_LOGIN:
return {
isLogin: true
}
case SET_LOGOUT:
return {
isLogin: false
}
default:
return state;
}
}
modules/index.js
import { combineReducers } from "redux";
import logincheck from "./logincheck";
const rootReducer = combineReducers({logincheck});
export default rootReducer;
2. Login 컴포넌트 생성
3. util 폴더 안에 cookie.js 생성
npm install react-cookie
util/cookie.js
import { Cookies } from 'react-cookie';
const cookies = new Cookies();
// 쿠키 생성함수
export const setCookie = (name,value,options)=> {
return cookies.set(name, value, {...options});
}
// 쿠키 접근함수
export const getCookie = (name) => {
return cookies.get(name);
}
// 쿠키 삭제함수
export const removeCookie = (name) => {
return cookies.remove(name);
}
components/Login.js
import React, { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import axios from 'axios';
import { API_URL } from '../config/conf';
import { setCookie } from '../util/cookie';
import { useDispatch } from 'react-redux';
import { goToHome, setLogin } from '../modules/logincheck';
const Login = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const [ loginData, setLoginData ] = useState({
usermail: "",
userpass: ""
})
const onChange = (e) => {
const { name, value } = e.target;
setLoginData({
...loginData,
[name]:value
})
}
const onSubmit = (e) => {
e.preventDefault();
// 인풋에 입력했는지 체크
if(loginData.usermail === '' || loginData.userpass === ''){
alert('이메일과 비밀번호를 입력해주세요');
}else {
axios.post(`${API_URL}/login`, loginData)
// 로그인이 되었을 때
.then(result=>{
let { usermail, username } = result.data;
console.log(result);
// usermail에 값이 있을 때
if(usermail !== null && usermail !== '' && usermail !== undefined){
alert('로그인되었습니다.');
// 현재시간 객체를 생성
let expires = new Date();
// 60분 더한 값으로 변경
expires.setMinutes(expires.getMinutes()+60);
setCookie('usermail', `${usermail}`, {path: '/', expires});
setCookie('username', `${username}`, {path: '/', expires});
dispatch(setLogin());
dispatch(goToHome(navigate));
}
})
.catch(e=>{
alert('이메일과 비밀번호를 확인해주세요');
})
}
}
return (
<div>
<form onSubmit={onSubmit}>
<p><input type="text" name="usermail" value={loginData.usermail} onChange={onChange}/></p>
<p><input type="password" name="userpass" value={loginData.userpass} onChange={onChange}/></p>
<p>
<button type="submit">로그인</button>
<Link to="/join"><button>회원가입</button></Link>
</p>
</form>
</div>
);
};
export default Login;
components/Header.js
import React, { useEffect } from 'react';
import { Link } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { getCookie, removeCookie } from '../util/cookie';
import { setLogout } from '../modules/logincheck';
const Header = () => {
const uname = getCookie('username');
const isLogin = useSelector(state=>state.logincheck.isLogin);
const dispatch = useDispatch();
const logoutClick = () => {
removeCookie('username');
removeCookie('usermail');
dispatch(setLogout());
}
useEffect(()=>{},[isLogin]);
return (
<div id="header">
<h1>그린고객센터</h1>
<ul>
<li><Link to="/">고객리스트보기</Link></li>
<li><Link to="/write">신규 고객 등록하기</Link></li>
{ isLogin &&
<>
<li>{uname}님 환영!</li>
<li onClick={logoutClick}>로그아웃</li>
<li>회원정보수정</li>
</>
}
{ isLogin ||
<>
<li><Link to="/login">로그인</Link></li>
<li><Link to="/join">회원가입</Link></li>
</>
}
<li>고객 검색</li>
</ul>
</div>
);
};
export default Header;
App.js
import './App.css';
import DetailCustomer from './components/DetailCustomer';
import Footer from './components/Footer';
import Header from './components/Header';
import { Route, Routes } from 'react-router-dom';
import EditCustomer from './components/EditCustomer';
import CustomerContainer from './components/CustomerContainer';
import CreateCustomerContainer from './components/CreateCustomerContainer';
import JoinForm from './components/JoinForm';
import Login from './components/Login';
function App() {
return (
<div className="App">
<Header/>
<Routes>
<Route path="/" element={<CustomerContainer />}/>
<Route path="/detailview/:no" element={<DetailCustomer/>}/>
<Route path="/write" element={<CreateCustomerContainer/>}/>
<Route path="/editCustomer/:no" element={<EditCustomer/>}/>
<Route path="/join" element={<JoinForm/>}/>
<Route path="/login" element={<Login/>}/>
</Routes>
<Footer/>
</div>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
import { applyMiddleware, legacy_createStore as createStore } from 'redux';
import rootReducer from './modules';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import { Provider } from 'react-redux';
import { CookiesProvider } from 'react-cookie';
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));
console.log(store.getState());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode>
<Provider store={store}>
<CookiesProvider>
<App />
</CookiesProvider>
</Provider>
</React.StrictMode>
</BrowserRouter>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();