※회원가입에 이메일 항목 추가
※정규표현식으로 이메일 형식 검사
※에러 사항을 alert 대신 input 하단에 표시되도록 수정
-백엔드-
model - <userModel.js> : email 추가
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
require: true,
unique: true,
},
password: {
type: String,
require: true,
},
email: { //email 추가
type: String,
require: true,
},
imageScore: {
type: Number,
default: 0,
},
combineScore: {
type: Number,
default: 0,
},
});
module.exports = mongoose.model("User", UserSchema);
controller - <userController.js>
※정규 표현식: 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어
-/^ : 시작, $/ : 끝
-[A-Za-z0-9] : 영문 대소문자 혹은 숫자로 시작
-([-_.][A-Za-z0-9]) : 두 번째 글자부터는 영문 대소문자 혹은 숫자이며 - _ .이 들어갈 수 있음
-* : 문자 또는 숫자가 반드시 있어야 함
-{2,3} : 2-3자리 지정
-i : 대소문자를 구분하지 않음
-test() : 문자열에 일치하는 부분이 있는지 확인하고, true 혹은 false로 return하는 메서드
(...)
//Post Login User, /login
const loginUser = asynchHandler(async (req, res) => {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) {
return res.status(401).json({ nameMessage: "일치하는 아이디가 없습니다." });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res
.status(401)
.json({ pwdMessage: "비밀번호가 일치하지 않습니다." });
}
const token = jwt.sign({ id: user._id }, jwtSecret);
res.cookie("token", token, { httpOnly: true });
res.status(200).json({ message: "로그인 성공", token });
});
//Post Register User, /register
const registerUser = asynchHandler(async (req, res) => {
const { username, password, chackPassword, email } = req.body;
//이메일 정규 표현식
const emailRegEx =
/^[A-Za-z0-9]([-_.]?[A-Za-z0-9])*@[A-Za-z0-9]([-_.]?[A-Za-z0-9])*\.[A-Za-z]{2,3}$/i;
const existingUser = await User.findOne({ username });
if (existingUser) {
return res.status(400).json({ nameMessage: "이미 사용중인 아이디입니다." });
}
if (password !== chackPassword) {
return res
.status(401)
.json({ pwdMessage: "비밀번호가 일치하지 않습니다." });
}
if (!emailRegEx.test(email)) { //이메일 형식 확인
return res
.status(401)
.json({
emailMessage: "이메일 형식이 올바르지 않습니다. ex) admin@aaa.com",
});
}
if (password === chackPassword) {
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({
username,
password: hashedPassword,
email,
});
res.status(201).json({ message: "회원가입 성공" });
}
});
(...)
-프론트엔드-
page - <Register.js> : 회원가입 페이지
※some() : 배열의 1개 요소라도 특정 조건을 충족하는지 확인하는 함수
import React, { useEffect, useState } from "react";
import axios from "axios";
import "../../css/user.css";
import { useNavigate } from "react-router-dom";
function Register() {
const navigate = useNavigate();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [password2, setPassword2] = useState("");
const [email, setEmail] = useState(""); //이메일 state
const [usernameError, setUsernameError] = useState(""); //아이디 에러
const [passwordError, setPasswordError] = useState(""); //비밀번호 에러
const [emailError, setEmailError] = useState(""); //이메일 에러
const changeUsername = (e) => setUsername(e.target.value);
const changePassword = (e) => setPassword(e.target.value);
const changePassword2 = (e) => setPassword2(e.target.value);
const changeEmail = (e) => setEmail(e.target.value); //이메일 onChange
const registerSubmit = async (e) => {
e.preventDefault();
const inputs = [username, password, password2, email]; //input 모음
const registerData = {
username: username,
password: password,
chackPassword: password2,
email: email,
};
if (inputs.some((input) => input === "")) { //input 모두 빈칸일 시
alert("빈칸을 입력해주세요.");
} else {
try {
await axios
.post("http://localhost:5000/register", registerData)
.then((res) => {
alert(res.data.message);
navigate("/");
});
} catch (err) {
setUsernameError(err.response.data.nameMessage); //아이디 에러 메시지
setPasswordError(err.response.data.pwdMessage); //비밀번호 에러 메시지
setEmailError(err.response.data.emailMessage); //이메일 에러 메시지
}
}
};
useEffect(() => {
if (localStorage.getItem("token") !== null) navigate("/main");
}, [navigate]);
return (
<div className="userContainer">
<h1>회원가입</h1>
<form onSubmit={registerSubmit}>
<div>
<label>아이디</label>
<input type="text" value={username} onChange={changeUsername} />
<h4>{usernameError}</h4>
</div>
<div>
<label>비밀번호</label>
<input type="password" value={password} onChange={changePassword} />
</div>
<div>
<label>비밀번호 확인</label>
<input type="password" value={password2} onChange={changePassword2} />
<h4>{passwordError}</h4>
</div>
<div>
<label>이메일</label>
<input
type="text"
value={email}
onChange={changeEmail}
placeholder="ex) admin@aaa.com"
/>
<h4>{emailError}</h4>
</div>
<button type="submit">회원가입</button>
</form>
<p onClick={() => navigate("/")}>-#로그인-</p>
</div>
);
}
export default Register;
page - <Login.js> : 로그인 페이지
import React, { useEffect, useState } from "react";
import axios from "axios";
import "../../css/user.css";
import { useNavigate } from "react-router-dom";
function Login() {
const navigate = useNavigate();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [usernameError, setUsernameError] = useState(""); //아이디 에러
const [passwordError, setPasswordError] = useState(""); //비밀번호 에러
const changeUsername = (e) => setUsername(e.target.value);
const changePassword = (e) => setPassword(e.target.value);
const loginSubmit = async (e) => {
e.preventDefault();
const loginData = { username: username, password: password };
if (username === "" || password === "") {
alert("빈칸을 입력해주세요.");
} else {
try {
await axios
.post("http://localhost:5000/login", loginData)
.then((res) => {
alert(res.data.message);
const { token } = res.data;
localStorage.setItem("token", token);
navigate("/main");
});
} catch (err) {
setUsernameError(err.response.data.nameMessage); //아이디 에러 메시지
setPasswordError(err.response.data.pwdMessage); //비밀번호 에러 메시지
}
}
};
useEffect(() => {
if (localStorage.getItem("token") !== null) navigate("/main");
}, [navigate]);
return (
<div className="userContainer">
<h1>로그인</h1>
<p></p>
<form onSubmit={loginSubmit}>
<div>
<label>아이디</label>
<input type="text" value={username} onChange={changeUsername} />
<h4>{usernameError}</h4>
</div>
<div>
<label>비밀번호</label>
<input type="password" value={password} onChange={changePassword} />
<h4>{passwordError}</h4>
</div>
<button type="submit">로그인</button>
</form>
<p onClick={() => navigate("/register")}>-#계정 생성-</p>
</div>
);
}
export default Login;
css - <user.css>
(...)
.userContainer h4 {
color: red;
height: 15px;
}
'프로젝트 > 로그인, 회원가입' 카테고리의 다른 글
6. 비밀번호 변경 (0) | 2024.05.27 |
---|---|
5. nodemailer, 인증코드 (0) | 2024.05.27 |
4. 아이디 찾기 (0) | 2024.05.24 |
2. JWT 토큰 검증 (0) | 2024.05.20 |
1. user 파일, score 파일 병합 (0) | 2024.05.20 |