📖 개요
완성된 화면 보기
👉 React
👉 로그인 성공
👉 로그인 실패
📁 폴더 구조
React로 로그인 화면 UI를 만들고, Axios POST로 MYSQL 저장되어 있는 IP, Password와 비교하는 로그인 기능까지 구현할 예정이다.
Client는 파일을 통일화해서 관리했다면, Server는 페이지 별로 폴더를 만들어 관리할 예정이다. 무조건 파일을 줄이고 통일화 시키는 것이 좋은 줄 알았는데, 홈페이지 같은 경우 페이지 별로 나눠 관리하는게 더 나을 수도 있다는 조언을 듣고 이런 결정을 하게 됐다. (확실히 폴더별로 나누니까 페이지에 에러가 났을 때, 파일 찾기 훨씬 수월했다.)
💻 DB 생성 및 값 넣기
로그인 기능을 구현하기에 앞서 ID와 Password를 저장할 DB를 먼저 만들겠다.
DB에 users라는 테이블을 만들고, ID, Password 컬럼을 만든다. (나는 회원가입 기능 안 만들고 로그인만 구현할 거라 심플하다.) ID와 Password로 쓸 값을 넣어준다.
CREATE TABLE `users` (
`ID` varchar(45) NOT NULL,
`Password` varchar(100) NOT NULL,
PRIMARY KEY (`ID`)
) ;
INSERT INTO server.users (ID, Password) VALUES ("nani", "password1234");
💻 로그인 화면 구현(React)
소스를 간단히 먼저 설명하자면, (전체코드도 아래에 있다.)
입력한 ID와 PW를 저장할 변수를 선언하고, handleInput함수를 통해 data의 변화를 감지해서 setInput 해준다.
const [inputId, setInputId] = useState('');
const [inputPw, setInputPw] = useState('');
const handleInputId = (e) => {
setInputId(e.target.value);
}
const handleInputPw = (e) => {
setInputPw(e.target.value);
}
ID와 PW를 입력하면 버튼 색을 변하게 하는 함수이다.
입력한 ID 길이와 PW 길이가 1보다 크면 setButton이 false가 된다. 이 때 <button>에서 disable이 false가 되면서 버튼이 활성화 된다.
const [button, setButton] = useState(true);
function changeButton(){
inputId.length > 1 && inputPw.length > 1 ? setButton(false) : setButton(true);
}
로그인이 성공하면 /main URL로 이동한다.
const goToMain = () => {
navigate('/main');
}
로그인 버튼을 누르면, url로 입력한 파라미터 값을 보낸다. 이 때 SUCCESS가 날라오면 goToMain 함수로 인해 화면이 이동하고, Fail이 날라오면 알람이 뜰 것이다.
const onClickLogin = async (e) => {
await axios({
url:'http://localhost:8000/Login/onLogin',
method:'POST',
headers: {
"Content-Type": "application/json"
},
params: {
'ID' : inputId,
'Password' : inputPw,
}
})
.then((res)=>{
if (res.data === 'SUCCESS'){
goToMain();
} else if(res.data === 'Fail'){
alert('아이디 또는 비밀번호가 일치하지 않습니다.');
}
})
}
html 부분을 간단히 설명하자면,
input에서 onChange를 감지하면 handleInput 함수로 값을 넘겨준다. 또한 onKeyUp 이벤트로 인해 키보드가 눌림을 감지하여 버튼을 활성화 시켜준다.
<div class="login-wrapper">
<img src={Logo} alt = "logo" width="200px" style = {{margin: "20px"}}/>
<form method="post" id="login-form" >
<input type="text" name ="ID" onChange={handleInputId} onKeyUp={changeButton} placeholder="아이디를 입력하세요."/>
<input type="password" name="PW" onChange={handleInputPw} onKeyUp={changeButton} placeholder="비밀번호를 입력하세요"/>
<button type ='button' onClick={onClickLogin} disabled={button}>로그인</button>
</form>
</div>
전체 코드
//Login_Page.js
import '../../css/login.css';
import { useState } from 'react';
import { useNavigate} from 'react-router-dom'
import axios from 'axios';
import Logo from '../../image/Logo.png';
function LoginPage() {
const navigate = useNavigate();
const [inputId, setInputId] = useState('');
const [inputPw, setInputPw] = useState('');
const [button, setButton] = useState(true);
function changeButton(){
inputId.length > 1 && inputPw.length > 1 ? setButton(false) : setButton(true);
}
const goToMain = () => {
navigate('/main');
}
// input data 의 변화가 있을 때마다 value 값을 변경해서 useState 해준다
const handleInputId = (e) => {
setInputId(e.target.value);
}
const handleInputPw = (e) => {
setInputPw(e.target.value);
}
const onClickLogin = async (e) => {
await axios({
url:'http://localhost:8000/Login/onLogin',
method:'POST',
headers: {
"Content-Type": "application/json"
},
params: {
'ID' : inputId,
'Password' : inputPw,
}
})
.then((res)=>{
if (res.data === 'SUCCESS'){
goToMain();
} else if(res.data === 'Fail'){
alert('아이디 또는 비밀번호가 일치하지 않습니다.');
}
})
}
return( <>
<div class="login-wrapper">
<img src={Logo} alt = "logo" width="200px" style = {{margin: "20px"}}/>
<form method="post" id="login-form" >
<input type="text" name ="username" onChange={handleInputId} onKeyUp={changeButton} placeholder="아이디를 입력하세요."/>
<input type="password" name="pwd" onChange={handleInputPw} onKeyUp={changeButton} placeholder="비밀번호를 입력하세요"/>
<button type ='button' onClick={onClickLogin} disabled={button}>로그인</button>
</form>
</div>
</>
)
}
export default LoginPage;
/*login.css*/
*{
padding: 0;
margin: 0;
border: none;
}
body{
font-size: 14px;
}
.login-wrapper{
width: 400px;
height: 400px;
padding: 40px;
box-sizing: border-box;
box-shadow: 0px 40px 30px -20px rgba(0, 0, 0, 0.3);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
#login-form > input{
width: 100%;
height: 48px;
padding: 0 10px;
box-sizing: border-box;
margin-bottom: 16px;
border-radius: 6px;
background-color: #F8F8F8;
}
#login-form > input::placeholder{
color: #D2D2D2;
}
#login-form > input[type="submit"]{
color: #fff;
font-size: 14px;
font-weight: bold;
background-color: #005bac;
margin-top: 20px;
cursor: pointer;
}
button{
width: 100%;
height: 48px;
padding: 0 10px;
color: #fff;
font-size: 14px;
font-weight: bold;
background-color: #005bac;
margin-top: 20px;
cursor: pointer;
&:disabled{
background-color: lightgray;
cursor: auto;
}
}
💻 로그인 기능 구현 (Server Post 요청)
server.js에 /Login 루트에 Login.js파일을 마운트 한다.
//server.js
const onLogin = require('./routes/Login');
app.use('/Login',onLogin);
localhost:8000/Login/onLogin으로 Post 요청이 들어오면,
ID 와 Password가 있는지 확인하고, DB에 해당 값이 있는지 검색한다. 값이 있어서 결과 값이 반환되면 SUCCESS를 응답으로 보내고, 없으면 Fail을 응답으로 보낸다.
//Login.js
const express = require('express');
const router = express.Router();
const db = require('../config/db');
router.post('/onLogin', function (req, res) {
// console.log(request);
var ID = req.query.ID;
var Password = req.query.Password;
console.log(ID);
console.log(Password);
if (ID && Password) {
db.query('SELECT * FROM users WHERE ID = ? AND Password = ?', [ID, Password], function (error, results, fields) {
console.log(results);
if (results.length > 0) { // ID, PW 일치함
console.log("Success!!");
res.send("SUCCESS");
} else {
res.send("Fail");
console.log("Fail!!!")
}
});
}
});
module.exports = router;
👻 마무리
로그인이 성공하면 쿠키를 생성해 저장하고, 로그인 안하면 다른 창 접근 못하는 접근제어 등은 프로젝트 마무리 쯤 진행할 예정이다. 미리 설정해두면 매번 로그인해야하는 귀찮음 때문에.. 😭😭
📌 참고 사이트
👉 React, Node.js와 MySQL을 이용한 로그인/회원가입 예제 (소스코드)
'💻 프로젝트 > 02. 사내 공지 데스크톱 앱' 카테고리의 다른 글
『Server 07 』[React] 버튼 클릭 시 페이지 이동 (0) | 2023.09.29 |
---|---|
『Server 06 』[React] 상단 메뉴바 (0) | 2023.09.20 |
『Client 04 』 [React] 게시판 만들기 -BoardList, props 전달, custom axios (0) | 2023.09.19 |
『Server 04 』[express] [mysql2] Node.js 서버 개설, DB 연동(GET) (0) | 2023.09.17 |
『Client 03 』 [React] [Electron] 정보 탭 CSS(Grid), 내 pc IP, Host 가져오기 (0) | 2023.09.17 |