티스토리 뷰

반응형

SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계

13단계 — 회원가입 시스템 만들기 (중복검사 + 비밀번호 정책 + 가입 후 자동 로그인)

12단계까지 오면서 우리는 이미 꽤 괜찮은 인증 시스템을 만들었습니다.

지금 상태:

bcrypt password
DB session
session expiry
session refresh
role
hooks auth
server guard

하지만 아직 하나 빠졌습니다.

새 사용자가 가입할 수 있는 기능

이번 단계에서는 다음을 구현합니다.

  • 회원가입 폼
  • username 중복 검사
  • 비밀번호 정책
  • bcrypt 해싱
  • 가입 후 자동 로그인 (session 생성)

이 단계가 끝나면 서비스의 기본 유저 시스템이 완성됩니다.


1️⃣ 회원가입 페이지 생성

파일 생성

src/routes/signup/+page.svelte
<script lang="ts">
	import { enhance } from '$app/forms';

	export let data: {
		error?: string;
		success?: boolean;
	};
</script>

<h1>회원가입</h1>

<form method="POST" use:enhance>
	<input
		type="text"
		name="username"
		placeholder="아이디"
		required
	/>

	<input
		type="password"
		name="password"
		placeholder="비밀번호"
		required
	/>

	<button type="submit">가입하기</button>
</form>

{#if data.error}
	<p style="color:red">{data.error}</p>
{/if}

여기서 중요한 것은:

form method="POST"

👉 여전히 API 없이 actions로 처리합니다


2️⃣ 회원가입 서버 로직 구현

반응형

파일 생성

src/routes/signup/+page.server.ts
import type { Actions, PageServerLoad } from './$types';
import { fail, redirect } from '@sveltejs/kit';
import { prisma } from '$lib/server/prisma';
import { hashPassword } from '$lib/server/password';
import { createSession } from '$lib/server/session.repo';

export const load: PageServerLoad = async ({ locals }) => {

	// 이미 로그인된 사용자는 홈으로
	if (locals.user) {
		throw redirect(302, '/');
	}

	return {};
};

export const actions: Actions = {

	default: async ({ request, cookies }) => {

		const data = await request.formData();

		const username = String(data.get('username') ?? '').trim();
		const password = String(data.get('password') ?? '').trim();

		if (!username || !password) {
			return fail(400, { error: '아이디와 비밀번호를 입력하세요.' });
		}

		// 비밀번호 정책
		if (password.length < 6) {
			return fail(400, { error: '비밀번호는 최소 6자 이상이어야 합니다.' });
		}

		// username 중복 검사
		const exists = await prisma.user.findUnique({
			where: { username }
		});

		if (exists) {
			return fail(400, { error: '이미 존재하는 아이디입니다.' });
		}

		// bcrypt 해싱
		const hashed = await hashPassword(password);

		const user = await prisma.user.create({
			data: {
				username,
				password: hashed,
				role: 'USER'
			}
		});

		// 가입 후 자동 로그인
		const session = await createSession(user.id);

		cookies.set('session_id', session.id, {
			path: '/',
			httpOnly: true,
			sameSite: 'lax'
		});

		throw redirect(302, '/');
	}
};

3️⃣ 레이아웃에 회원가입 링크 추가

src/routes/+layout.svelte

{#if data.isLoggedIn}
	<form method="POST" action="/logout">
		<button>로그아웃</button>
	</form>
{:else}
	<a href="/login">로그인</a>
	<a href="/signup">회원가입</a>
{/if}

4️⃣ 실제 동작 확인

1️⃣ /signup 이동

가입 폼 표시


2️⃣ 신규 계정 생성

예:

username = hello
password = 123456

3️⃣ 자동 로그인

회원가입 후

session 생성
cookie 저장
redirect /

4️⃣ DB 확인

User 테이블

id
username
password (bcrypt)
role
createdAt

Session 테이블

session_id
userId
expiresAt

5️⃣ 지금까지 완성된 인증 시스템 구조

현재 시스템은 다음 구조입니다.

signup
login
logout

bcrypt password
session DB
session expiry
session refresh

hooks authentication
locals.user

requireLogin
requireRole

이건 주니어 사이드 프로젝트 수준을 이미 넘은 구조입니다.


6️⃣ 보안적으로 더 개선할 수 있는 것

다음 단계에서 할 것들:

이메일 인증

signup
→ email verify
→ activate account

비밀번호 정책 강화

8자 이상
특수문자
숫자

로그인 시도 제한

5회 실패 → 잠금

rate limit

IP 기반 로그인 제한

오늘 단계 핵심 한 문장

회원가입은 “유저 생성”이 아니라
“인증 시스템의 시작점”이다.


 

SvelteKit, 회원가입구현, SSR인증, bcrypt, Prisma, MySQL, 세션관리, 주니어개발자, 백엔드기초, 풀스택

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함
반응형