티스토리 뷰
SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계
10단계 — Role 기반 권한(ADMIN/USER) 분리하기 (관리자 페이지 보호까지)
9단계에서 “로그인 안 하면 못 들어오게” 서버에서 막는 걸 했죠.
근데 실무에서는 로그인만으로 끝나지 않아요.
“로그인한 사람 누구나 삭제 버튼 누르면요?”
“관리자 페이지는 관리자만 들어가야 하잖아요?”
그래서 10단계는 Role(권한) 을 붙입니다.
- USER: 일반 사용자
- ADMIN: 관리자
그리고 중요한 원칙 하나:
권한도 서버에서 판단한다.
(버튼 숨기는 건 UX일 뿐)
10단계 목표
- locals.user에 role을 포함한다
- requireLogin을 확장해 requireRole 가드를 만든다
- /admin 페이지를 관리자만 접근 가능하게 막는다
- UI에서도 “보이는 것”만 다르게 하되, 진짜 차단은 서버에서 한다
Step 10-1. 사용자 모델에 role을 추가한다 (이번 단계는 하드코딩)
아직 유저 테이블을 안 만들었으니까,
8단계에서 하드코딩했던 USER 객체에 role을 붙이겠습니다.
src/routes/login/+page.server.ts 수정
import type { Actions, PageServerLoad } from './$types';
import { fail, redirect } from '@sveltejs/kit';
const USER = {
username: 'user',
password: '1234',
id: '2',
role: 'USER' as const
};
const ADMIN = {
username: 'admin',
password: '1234',
id: '1',
role: 'ADMIN' as const
};
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') ?? '');
const password = String(data.get('password') ?? '');
let matched: typeof USER | typeof ADMIN | null = null;
if (username === USER.username && password === USER.password) matched = USER;
if (username === ADMIN.username && password === ADMIN.password) matched = ADMIN;
if (!matched) {
return fail(400, { error: '아이디 또는 비밀번호가 틀렸습니다.' });
}
// ✅ user_id 뿐 아니라 role도 쿠키로 저장 (단순 예제)
cookies.set('user_id', matched.id, {
path: '/',
httpOnly: true,
sameSite: 'lax'
});
cookies.set('user_role', matched.role, {
path: '/',
httpOnly: true,
sameSite: 'lax'
});
throw redirect(302, '/');
}
};
⚠️ 실무에서는 role을 쿠키에 그대로 넣기보단
세션 DB에서 role을 조회하는 구조가 더 안전합니다.
하지만 지금은 “흐름 이해”가 목표라 단순화합니다.
Step 10-2. hooks에서 role까지 locals에 심기
src/hooks.server.ts 수정
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const userId = event.cookies.get('user_id');
const role = event.cookies.get('user_role');
if (userId && (role === 'ADMIN' || role === 'USER')) {
event.locals.user = { id: userId, role };
} else {
event.locals.user = null;
}
return resolve(event);
};
Step 10-3. locals 타입 업데이트 (TypeScript)
src/app.d.ts 수정
declare namespace App {
interface Locals {
user: {
id: string;
role: 'ADMIN' | 'USER';
} | null;
}
}
Step 10-4. 권한 가드 유틸 만들기 (핵심)
src/lib/server/auth.ts 수정/생성
import { redirect, error } from '@sveltejs/kit';
import type { RequestEvent } from '@sveltejs/kit';
export function requireLogin(event: RequestEvent) {
if (!event.locals.user) {
throw redirect(302, '/login');
}
return event.locals.user;
}
export function requireRole(event: RequestEvent, role: 'ADMIN' | 'USER') {
const user = requireLogin(event);
if (user.role !== role) {
// 권한 없음
throw error(403, '권한이 없습니다.');
}
return user;
}
- requireLogin: 로그인 여부 체크
- requireRole: 로그인 체크 + role 체크
👉 이제 권한 보호는 “한 줄”입니다.
Step 10-5. 관리자 페이지 만들기
1) 페이지 UI
src/routes/admin/+page.svelte
<script lang="ts">
export let data: { userId: string };
</script>
<h1>Admin Page</h1>
<p>관리자만 접근 가능. userId = {data.userId}</p>
2) 서버 가드 적용
src/routes/admin/+page.server.ts
import type { PageServerLoad } from './$types';
import { requireRole } from '$lib/server/auth';
export const load: PageServerLoad = async (event) => {
const user = requireRole(event, 'ADMIN');
return {
userId: user.id
};
};
Step 10-6. 레이아웃에 role 표시 + 메뉴 분기 (UX)
src/routes/+layout.svelte 일부 수정 예시
<nav>
<a href="/">Home</a>
<a href="/dashboard">Dashboard</a>
{#if data.user?.role === 'ADMIN'}
<a href="/admin">Admin</a>
{/if}
</nav>
👉 이건 UX 편의입니다.
보안은 이미 서버에서 막고 있습니다.
Step 10-7. 동작 확인 시나리오
1) USER로 로그인
- username: user
- password: 1234
✅ /dashboard 가능
❌ /admin → 403
2) ADMIN으로 로그인
- username: admin
- password: 1234
✅ /admin 가능
✅ Admin 메뉴 보임
여기서 주니어가 꼭 알아야 할 “실무 감각”
1) Role 체크는 무조건 서버에서
- 프론트는 숨기는 용도
- 진짜 차단은 +page.server.ts
2) 권한 정책은 중앙화
- requireRole 같은 유틸로 모아야
- 페이지 늘어도 관리 가능
3) 쿠키에 role 저장은 “학습용”
실무에선 이렇게 가는 게 일반적입니다.
- 쿠키에는 세션 id만
- hooks에서 세션 조회 → role 로딩
- locals에 role 세팅
(다음 단계에서 이 구조로 진짜 업그레이드합니다.)
SvelteKit,SSR,RoleBasedAccessControl,RBAC,권한관리,관리자페이지,주니어개발자,백엔드기초,hooksServer,풀스택
'study > 백엔드' 카테고리의 다른 글
| SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계 (0) | 2026.03.05 |
|---|---|
| SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계 (0) | 2026.03.02 |
| SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계 (0) | 2026.02.09 |
| SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계 (0) | 2026.01.29 |
| SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계 (0) | 2026.01.28 |
- Total
- Today
- Yesterday
- Express
- fastapi
- DevOps
- 딥러닝
- Prisma
- LangChain
- llm
- node.js
- flax
- Docker
- SEO최적화
- REACT
- 압박면접
- 백엔드개발
- kotlin
- NestJS
- ai철학
- JAX
- 웹개발
- Redis
- seo 최적화 10개
- CI/CD
- Python
- PostgreSQL
- 개발블로그
- nextJS
- Next.js
- JWT
- rag
- 쿠버네티스
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 |
