사용자 로직 수정
This commit is contained in:
@@ -10,26 +10,26 @@ require('dotenv').config();
|
|||||||
// 로그인
|
// 로그인
|
||||||
exports.login = async (req, res) => {
|
exports.login = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { email, password } = req.body;
|
const { username, password } = req.body;
|
||||||
|
|
||||||
// 이메일 필수 확인
|
// 사용자명 필수 확인
|
||||||
if (!email) {
|
if (!username) {
|
||||||
return res.status(400).json({ message: '이메일은 필수 항목입니다.' });
|
return res.status(400).json({ message: '사용자명은 필수 항목입니다.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 사용자 조회
|
// 사용자 조회
|
||||||
const user = await User.findOne({ where: { email } });
|
const user = await User.findOne({ where: { username } });
|
||||||
|
|
||||||
// 사용자가 존재하지 않는 경우
|
// 사용자가 존재하지 않는 경우
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return res.status(401).json({ message: '이메일 또는 비밀번호가 올바르지 않습니다.' });
|
return res.status(401).json({ message: '사용자명 또는 비밀번호가 올바르지 않습니다.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 비밀번호 검증
|
// 비밀번호 검증
|
||||||
const isPasswordValid = await user.validatePassword(password);
|
const isPasswordValid = await user.validatePassword(password);
|
||||||
|
|
||||||
if (!isPasswordValid) {
|
if (!isPasswordValid) {
|
||||||
return res.status(401).json({ message: '이메일 또는 비밀번호가 올바르지 않습니다.' });
|
return res.status(401).json({ message: '사용자명 또는 비밀번호가 올바르지 않습니다.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 마지막 로그인 시간 업데이트
|
// 마지막 로그인 시간 업데이트
|
||||||
@@ -39,6 +39,7 @@ exports.login = async (req, res) => {
|
|||||||
const token = jwt.sign(
|
const token = jwt.sign(
|
||||||
{
|
{
|
||||||
id: user.id,
|
id: user.id,
|
||||||
|
username: user.username,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
role: user.role,
|
role: user.role,
|
||||||
name: user.name
|
name: user.name
|
||||||
@@ -70,6 +71,7 @@ exports.login = async (req, res) => {
|
|||||||
const userData = {
|
const userData = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
|
username: user.username,
|
||||||
email: user.email,
|
email: user.email,
|
||||||
role: user.role,
|
role: user.role,
|
||||||
status: user.status,
|
status: user.status,
|
||||||
@@ -90,26 +92,33 @@ exports.login = async (req, res) => {
|
|||||||
// 회원가입
|
// 회원가입
|
||||||
exports.register = async (req, res) => {
|
exports.register = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { name, email, password, role, status } = req.body;
|
const { name, email, username, password, role, status } = req.body;
|
||||||
|
|
||||||
// 필수 필드 검증
|
// 필수 필드 검증
|
||||||
if (!name || !email || !password) {
|
if (!name || !email || !username || !password) {
|
||||||
return res.status(400).json({ message: '이름, 이메일, 비밀번호는 필수 항목입니다.' });
|
return res.status(400).json({ message: '이름, 이메일, 사용자명, 비밀번호는 필수 항목입니다.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 이메일 중복 확인
|
// 이메일 중복 확인
|
||||||
const existingUser = await User.findOne({ where: { email } });
|
const existingEmail = await User.findOne({ where: { email } });
|
||||||
|
|
||||||
if (existingUser) {
|
if (existingEmail) {
|
||||||
return res.status(400).json({ message: '이미 등록된 이메일입니다.' });
|
return res.status(400).json({ message: '이미 등록된 이메일입니다.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 사용자명 중복 확인
|
||||||
|
const existingUsername = await User.findOne({ where: { username } });
|
||||||
|
|
||||||
|
if (existingUsername) {
|
||||||
|
return res.status(400).json({ message: '이미 사용 중인 사용자명입니다.' });
|
||||||
|
}
|
||||||
|
|
||||||
// 사용자 생성
|
// 사용자 생성
|
||||||
const newUser = await User.create({
|
const newUser = await User.create({
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
|
username,
|
||||||
password,
|
password,
|
||||||
username: email,
|
|
||||||
role: role || 'user',
|
role: role || 'user',
|
||||||
status: status || 'active'
|
status: status || 'active'
|
||||||
});
|
});
|
||||||
@@ -118,6 +127,7 @@ exports.register = async (req, res) => {
|
|||||||
const userResponse = {
|
const userResponse = {
|
||||||
id: newUser.id,
|
id: newUser.id,
|
||||||
name: newUser.name,
|
name: newUser.name,
|
||||||
|
username: newUser.username,
|
||||||
email: newUser.email,
|
email: newUser.email,
|
||||||
role: newUser.role,
|
role: newUser.role,
|
||||||
status: newUser.status,
|
status: newUser.status,
|
||||||
@@ -197,8 +207,8 @@ exports.updateProfile = async (req, res) => {
|
|||||||
// 프로필 업데이트
|
// 프로필 업데이트
|
||||||
const updateData = {
|
const updateData = {
|
||||||
name: name || user.name,
|
name: name || user.name,
|
||||||
email: email || user.email,
|
email: email || user.email
|
||||||
username: email || user.email // username도 이메일과 동일하게 업데이트
|
// username은 변경하지 않음 - 로그인 식별자로 사용되기 때문
|
||||||
};
|
};
|
||||||
|
|
||||||
// 비밀번호가 제공된 경우에만 업데이트
|
// 비밀번호가 제공된 경우에만 업데이트
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const { DataTypes } = require('sequelize');
|
const { DataTypes } = require('sequelize');
|
||||||
const { sequelize } = require('../config/database');
|
const { sequelize } = require('../config/database');
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
|
const { encrypt, decrypt } = require('../utils/encryption');
|
||||||
|
|
||||||
const User = sequelize.define('User', {
|
const User = sequelize.define('User', {
|
||||||
id: {
|
id: {
|
||||||
@@ -32,7 +33,14 @@ const User = sequelize.define('User', {
|
|||||||
validate: {
|
validate: {
|
||||||
isEmail: true
|
isEmail: true
|
||||||
},
|
},
|
||||||
comment: '이메일'
|
comment: '이메일 (암호화됨)',
|
||||||
|
get() {
|
||||||
|
const rawValue = this.getDataValue('email');
|
||||||
|
return rawValue ? decrypt(rawValue) : null;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
this.setDataValue('email', value ? encrypt(value) : null);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
role: {
|
role: {
|
||||||
type: DataTypes.ENUM('admin', 'clubadmin', 'user'),
|
type: DataTypes.ENUM('admin', 'clubadmin', 'user'),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import apiClient from './api';
|
|||||||
const authService = {
|
const authService = {
|
||||||
/**
|
/**
|
||||||
* 로그인
|
* 로그인
|
||||||
* @param {Object} credentials - 로그인 정보 (이메일, 비밀번호)
|
* @param {Object} credentials - 로그인 정보 (사용자명, 비밀번호)
|
||||||
* @returns {Promise} - 로그인 결과
|
* @returns {Promise} - 로그인 결과
|
||||||
*/
|
*/
|
||||||
login(credentials) {
|
login(credentials) {
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<h2>볼링 클럽 매니저 로그인</h2>
|
<h2>볼링 클럽 매니저 로그인</h2>
|
||||||
<form @submit.prevent="handleLogin" v-if="!showRegisterForm">
|
<form @submit.prevent="handleLogin" v-if="!showRegisterForm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email">이메일</label>
|
<label for="username">사용자명</label>
|
||||||
<InputText id="email" v-model="email" class="w-full" :class="{'p-invalid': emailError}" />
|
<InputText id="username" v-model="username" class="w-full" :class="{'p-invalid': usernameError}" />
|
||||||
<small v-if="emailError" class="p-error">{{ emailError }}</small>
|
<small v-if="usernameError" class="p-error">{{ usernameError }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">비밀번호</label>
|
<label for="password">비밀번호</label>
|
||||||
@@ -29,6 +29,12 @@
|
|||||||
<!-- 회원가입 폼 -->
|
<!-- 회원가입 폼 -->
|
||||||
<form @submit.prevent="handleRegister" v-if="showRegisterForm">
|
<form @submit.prevent="handleRegister" v-if="showRegisterForm">
|
||||||
<h3>회원가입</h3>
|
<h3>회원가입</h3>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="registerUsername">사용자명(로그인 아이디)</label>
|
||||||
|
<InputText id="registerUsername" v-model="registerUsername" class="w-full" :class="{'p-invalid': registerUsernameError}" />
|
||||||
|
<small v-if="registerUsernameError" class="p-error">{{ registerUsernameError }}</small>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="registerName">이름</label>
|
<label for="registerName">이름</label>
|
||||||
<InputText id="registerName" v-model="registerName" class="w-full" :class="{'p-invalid': registerNameError}" />
|
<InputText id="registerName" v-model="registerName" class="w-full" :class="{'p-invalid': registerNameError}" />
|
||||||
@@ -58,10 +64,7 @@
|
|||||||
class="w-full" />
|
class="w-full" />
|
||||||
<small v-if="registerPasswordConfirmError" class="p-error">{{ registerPasswordConfirmError }}</small>
|
<small v-if="registerPasswordConfirmError" class="p-error">{{ registerPasswordConfirmError }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<label for="registerPhone">전화번호 (선택)</label>
|
|
||||||
<InputText id="registerPhone" v-model="registerPhone" class="w-full" />
|
|
||||||
</div>
|
|
||||||
<Button type="submit" label="회원가입" class="w-full" :loading="loading" />
|
<Button type="submit" label="회원가입" class="w-full" :loading="loading" />
|
||||||
<div class="login-link">
|
<div class="login-link">
|
||||||
<p>이미 계정이 있으신가요? <a href="#" @click.prevent="showRegisterForm = false">로그인</a></p>
|
<p>이미 계정이 있으신가요? <a href="#" @click.prevent="showRegisterForm = false">로그인</a></p>
|
||||||
@@ -82,21 +85,22 @@ const user = inject('user');
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const email = ref('');
|
const username = ref('');
|
||||||
const password = ref('');
|
const password = ref('');
|
||||||
const rememberMe = ref(false);
|
const rememberMe = ref(false);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const emailError = ref('');
|
const usernameError = ref('');
|
||||||
const passwordError = ref('');
|
const passwordError = ref('');
|
||||||
|
|
||||||
// 회원가입 관련 상태
|
// 회원가입 폼 상태
|
||||||
const showRegisterForm = ref(false);
|
const showRegisterForm = ref(false);
|
||||||
const registerName = ref('');
|
const registerName = ref('');
|
||||||
|
const registerUsername = ref('');
|
||||||
const registerEmail = ref('');
|
const registerEmail = ref('');
|
||||||
const registerPassword = ref('');
|
const registerPassword = ref('');
|
||||||
const registerPasswordConfirm = ref('');
|
const registerPasswordConfirm = ref('');
|
||||||
const registerPhone = ref('');
|
|
||||||
const registerNameError = ref('');
|
const registerNameError = ref('');
|
||||||
|
const registerUsernameError = ref('');
|
||||||
const registerEmailError = ref('');
|
const registerEmailError = ref('');
|
||||||
const registerPasswordError = ref('');
|
const registerPasswordError = ref('');
|
||||||
const registerPasswordConfirmError = ref('');
|
const registerPasswordConfirmError = ref('');
|
||||||
@@ -108,18 +112,16 @@ const passwordHasLowercase = computed(() => /[a-z]/.test(registerPassword.value)
|
|||||||
const passwordHasNumber = computed(() => /[0-9]/.test(registerPassword.value));
|
const passwordHasNumber = computed(() => /[0-9]/.test(registerPassword.value));
|
||||||
const passwordHasSpecial = computed(() => /[!@#$%^&*(),.?":{}|<>]/.test(registerPassword.value));
|
const passwordHasSpecial = computed(() => /[!@#$%^&*(),.?":{}|<>]/.test(registerPassword.value));
|
||||||
|
|
||||||
|
// 폼 유효성 검사
|
||||||
const validateForm = () => {
|
const validateForm = () => {
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
|
|
||||||
// 이메일 유효성 검사
|
// 사용자명 검증
|
||||||
if (!email.value) {
|
if (!username.value) {
|
||||||
emailError.value = '이메일을 입력해주세요.';
|
usernameError.value = '사용자명을 입력해주세요.';
|
||||||
isValid = false;
|
|
||||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)) {
|
|
||||||
emailError.value = '유효한 이메일 주소를 입력해주세요.';
|
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
emailError.value = '';
|
usernameError.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 비밀번호 유효성 검사
|
// 비밀번호 유효성 검사
|
||||||
@@ -137,7 +139,7 @@ const validateForm = () => {
|
|||||||
const validateRegisterForm = () => {
|
const validateRegisterForm = () => {
|
||||||
let isValid = true;
|
let isValid = true;
|
||||||
|
|
||||||
// 이름 유효성 검사
|
// 이름 검증
|
||||||
if (!registerName.value) {
|
if (!registerName.value) {
|
||||||
registerNameError.value = '이름을 입력해주세요.';
|
registerNameError.value = '이름을 입력해주세요.';
|
||||||
isValid = false;
|
isValid = false;
|
||||||
@@ -145,11 +147,22 @@ const validateRegisterForm = () => {
|
|||||||
registerNameError.value = '';
|
registerNameError.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 이메일 유효성 검사
|
// 사용자명 검증
|
||||||
|
if (!registerUsername.value) {
|
||||||
|
registerUsernameError.value = '사용자명을 입력해주세요.';
|
||||||
|
isValid = false;
|
||||||
|
} else if (registerUsername.value.length < 4) {
|
||||||
|
registerUsernameError.value = '사용자명은 최소 4자 이상이어야 합니다.';
|
||||||
|
isValid = false;
|
||||||
|
} else {
|
||||||
|
registerUsernameError.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 이메일 검증
|
||||||
if (!registerEmail.value) {
|
if (!registerEmail.value) {
|
||||||
registerEmailError.value = '이메일을 입력해주세요.';
|
registerEmailError.value = '이메일을 입력해주세요.';
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(registerEmail.value)) {
|
} else if (!/^\S+@\S+\.\S+$/.test(registerEmail.value)) {
|
||||||
registerEmailError.value = '유효한 이메일 주소를 입력해주세요.';
|
registerEmailError.value = '유효한 이메일 주소를 입력해주세요.';
|
||||||
isValid = false;
|
isValid = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -193,7 +206,7 @@ const handleLogin = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await authService.login({
|
const response = await authService.login({
|
||||||
email: email.value,
|
username: username.value,
|
||||||
password: password.value
|
password: password.value
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -239,9 +252,9 @@ const handleRegister = async () => {
|
|||||||
try {
|
try {
|
||||||
await authService.register({
|
await authService.register({
|
||||||
name: registerName.value,
|
name: registerName.value,
|
||||||
|
username: registerUsername.value,
|
||||||
email: registerEmail.value,
|
email: registerEmail.value,
|
||||||
password: registerPassword.value,
|
password: registerPassword.value
|
||||||
phone: registerPhone.value
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 회원가입 성공 메시지
|
// 회원가입 성공 메시지
|
||||||
@@ -250,16 +263,16 @@ const handleRegister = async () => {
|
|||||||
// 로그인 폼으로 전환
|
// 로그인 폼으로 전환
|
||||||
showRegisterForm.value = false;
|
showRegisterForm.value = false;
|
||||||
|
|
||||||
// 입력한 이메일을 로그인 폼에 자동 입력
|
// 입력한 사용자명을 로그인 폼에 자동 입력
|
||||||
email.value = registerEmail.value;
|
username.value = registerUsername.value;
|
||||||
password.value = '';
|
password.value = '';
|
||||||
|
|
||||||
// 회원가입 폼 초기화
|
// 회원가입 폼 초기화
|
||||||
registerName.value = '';
|
registerName.value = '';
|
||||||
|
registerUsername.value = '';
|
||||||
registerEmail.value = '';
|
registerEmail.value = '';
|
||||||
registerPassword.value = '';
|
registerPassword.value = '';
|
||||||
registerPasswordConfirm.value = '';
|
registerPasswordConfirm.value = '';
|
||||||
registerPhone.value = '';
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('회원가입 오류:', error);
|
console.error('회원가입 오류:', error);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user