📘 Aura_AI Day 8
자체 회원가입 / 로그인 기능 완성 + MySQL 연동 정리
안녕하세요.
오늘은 Google OAuth에 더해 자체 회원가입 / 로그인 기능을 완성하고,
이를 MySQL DB 저장 구조와 함께 안정적으로 연결했습니다.
UI 구현보다는
👉 **“인증 시스템을 실제 서비스 수준으로 완성하는 것”**에 초점을 둔 하루였습니다.
🎯 Day 8 목표
- 회원가입 정보를 MySQL DB에 저장
- 이메일 / 비밀번호 기반 로그인 구현
- 입력값 유효성 검사(Regex) 적용
- 이메일 / 닉네임 중복 체크
- 회원가입 후 자동 로그인 → /chat 이동
✅ 오늘 추가된 기능 요약
- 회원가입 데이터 MySQL 저장
- Credentials 기반 로그인(Auth.js)
- 회원가입 후 자동 로그인 처리
- 클라이언트 + 서버 이중 Regex 검증
- 이메일 / 닉네임 중복 체크
- 로그인 실패 UX 개선
1️⃣ 오늘 설치한 패키지
npm install mysql2 bcryptjs
왜 이 패키지들인가?
- mysql2
- Promise 기반 API 지원
- Connection Pool 제공 → 실무 표준
- bcryptjs
- 비밀번호 단방향 해시
- 평문 저장 ❌, 복호화 ❌ → 보안 필수
2️⃣ DB 설계 (MySQL)
2-1. 데이터베이스 생성
CREATE DATABASE aura_ai
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
이모지, 한글까지 안전하게 저장하기 위해 utf8mb4 사용
2-2. users 테이블 구조
CREATE TABLE users (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL,
phone VARCHAR(30) NOT NULL,
region VARCHAR(50) NOT NULL,
nickname VARCHAR(50) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY uniq_email (email),
UNIQUE KEY uniq_nickname (nickname)
);
📌 설계 포인트
- password ❌ → password_hash만 저장
- 이메일 / 닉네임은 DB 레벨에서 UNIQUE
- 코드 + DB 2중 방어
3️⃣ 기능 코드 핵심 설명
✅ 3-1. MySQL 연결 풀 생성 (db.ts)
import mysql from "mysql2/promise";
const pool = mysql.createPool({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
port: process.env.MYSQL_PORT ? Number(process.env.MYSQL_PORT) : 3306,
connectionLimit: 10,
});
export default pool;
왜 Connection Pool인가?
- 요청마다 연결 생성 ❌ (비효율)
- 풀에서 재사용 → 성능 & 안정성
- 실무에서 가장 일반적인 DB 접근 방식
✅ 3-2. 회원가입 API (route.ts)
전체 흐름
- 입력값 추출
- Regex 유효성 검사
- DB 중복 체크
- 비밀번호 해시
- 회원 저장
① Regex 유효성 검사
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRegex = /^01[016789]-?\d{3,4}-?\d{4}$/;
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d).{8,}$/;
if (!emailRegex.test(email)) return Response.json({}, { status: 400 });
if (!phoneRegex.test(phone)) return Response.json({}, { status: 400 });
if (!passwordRegex.test(password)) return Response.json({}, { status: 400 });
📌 왜 서버에서도 검사할까?
- 클라이언트 검증은 우회 가능
- 서버 검증은 신뢰 가능한 최종 방어선
② 이메일 / 닉네임 중복 체크
SELECT id FROM users WHERE email = ? OR nickname = ?
- 중복 시 409 Conflict
- UX + API 의미 모두 명확
③ 비밀번호 해시 후 저장
const hashedPassword = await bcrypt.hash(password, 12);
- 원본 비밀번호는 절대 저장하지 않음
- 12 rounds → 보안과 성능 균형
✅ 3-3. Credentials 로그인 추가 (auth.ts)
Credentials({
async authorize(credentials) {
const identifier = credentials.identifier;
const password = credentials.password;
const [rows] = await pool.execute(
"SELECT id, name, email, password_hash FROM users WHERE email = ? LIMIT 1",
[identifier]
);
const isValid = await bcrypt.compare(password, user.password_hash);
if (!isValid) return null;
return { id, name, email };
},
});
📌 핵심 개념
- Credentials Provider는 직접 인증 로직을 구현
- DB 조회 → bcrypt 비교
- 성공 시 유저 객체 반환
- 실패 시 null → Auth.js가 로그인 실패 처리
✅ 3-4. 회원가입 후 자동 로그인
const signInResult = await signIn("credentials", {
identifier: payload.email,
password,
callbackUrl: "/chat",
redirect: false,
});
if (signInResult?.url) {
window.location.href = signInResult.url;
}
왜 자동 로그인?
- 회원가입 → 로그인 재입력 ❌
- UX 개선 + 이탈률 감소
- 실제 서비스에서 매우 일반적인 패턴
✅ 3-5. 로그인 UX 개선
if (!email || !password) {
alert("이메일과 비밀번호를 입력해주세요.");
}
if (result?.error) {
alert("이메일 또는 비밀번호를 확인해주세요.");
}
- 실패 원인을 명확하게 안내
- 단순 alert이지만 UX 의도는 분명
4️⃣ 오늘 변경된 파일 정리
📂 신규 파일
- db.ts — MySQL 연결 풀
- route.ts — 회원가입 API
✏️ 수정 파일
- auth.ts — Credentials Provider 추가
- page.tsx
- Regex 검증
- 회원가입 후 자동 로그인
- 로그인 실패 UX 개선
5️⃣ 오늘의 실무 포인트 정리
- ✅ 비밀번호는 반드시 해시 저장
- ✅ 검증은 프론트 + 서버 이중 처리
- ✅ 중복 체크는 DB UNIQUE로 마무리
- ✅ 회원가입 후 자동 로그인으로 UX 개선
- ✅ OAuth + Credentials 공존 구조 완성
✅ Day 8 결과 체크리스트
- 회원가입 정보 DB 저장
- 이메일 / 비밀번호 로그인 가능
- Regex 유효성 검사
- 이메일 / 닉네임 중복 체크
- 회원가입 후 /chat 이동
'챗봇 공부 노트' 카테고리의 다른 글
| [10편] FastAPI 백엔드 분리 & 프론트엔드 연동 (1) | 2026.01.26 |
|---|---|
| [9편] Zustand로 인증 상태 통합 (0) | 2026.01.25 |
| [7편] Google OAuth 인증 체계 구축 (1) | 2026.01.21 |
| [6편] MyPage분리 + 채팅 검색 기능 추가 (0) | 2026.01.20 |
| [5편] chat 관련 ui 페이지 추가 (0) | 2026.01.18 |