일상이 개발
Next.js 접근 제어 & 권한 분기 완전 정복 – 로그인 보호부터 Role 기반 렌더링까지 실전 가이드
아빠고미
2025. 5. 17. 12:57
반응형
Next.js 앱에서 접근 제어와 권한 분기 처리 전략 – 페이지 보호부터 역할 기반 UI 렌더링까지 실전 설계 가이드
Next.js 앱에서 보안을 위해 꼭 필요한 요소가 있습니다. 바로 접근 제어와 권한 분기 처리입니다.
사용자가 로그인하지 않았거나, 권한이 없는 페이지에 접근했을 때 적절한 리디렉션과 UI 분기 처리가 이루어지지 않는다면 서비스 신뢰도는 물론 보안상 허점까지 생길 수 있습니다.
이번 글에서는 다음 내용을 중심으로 Next.js 접근 제어 전략을 실전 코드 중심으로 구성합니다:
- ✅ 페이지 단위 보호 (SSR/CSR)
- ✅ 미들웨어 인증 라우팅 처리
- ✅ 권한(Role) 기반 조건 렌더링
- ✅ 사용자 유형에 따른 네비게이션 분리
- ✅ UX를 해치지 않는 분기 처리 기법
1. 🔐 인증되지 않은 사용자의 페이지 접근 차단
✅ 기본 흐름
- 1. 인증 토큰 존재 여부 확인 (SSR or CSR)
- 2. 인증되지 않은 경우 → 로그인 페이지로 redirect
📦 SSR 방식 예시 (getServerSideProps)
export async function getServerSideProps(context) {
const token = context.req.cookies.token;
if (!token) {
return {
redirect: {
destination: '/login',
permanent: false
}
};
}
return {
props: {}
};
}
📦 CSR 방식 예시 (useEffect + router)
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { useAuth } from '@/store/auth';
export default function ProtectedPage() {
const router = useRouter();
const { user } = useAuth();
useEffect(() => {
if (!user) {
router.replace('/login');
}
}, [user]);
return <div>이 페이지는 로그인된 사용자만 볼 수 있습니다.</div>;
}
➡️ SSR은 SEO와 초기 데이터 처리에 강하고, CSR은 UX 중심의 리액티브 제어에 강합니다.
2. ✨ 미들웨어를 통한 인증 라우팅 제어 (Next.js 13+)
✅ 왜 미들웨어를 쓸까?
- 라우팅 단계에서 인증 여부 확인
- SSR보다 빠르게 리디렉션 가능
- 프론트 보호를 더 단단하게
📦 middleware.ts 예시
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('token')?.value;
const pathname = request.nextUrl.pathname;
const isProtected = pathname.startsWith('/dashboard') || pathname.startsWith('/admin');
if (isProtected && !token) {
const loginUrl = new URL('/login', request.url);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
📌 설정 필요
// next.config.js
module.exports = {
matcher: ['/dashboard/:path*', '/admin/:path*']
}
➡️ 미들웨어를 활용하면 모든 페이지 접근 이전에 인증 상태를 먼저 검증할 수 있습니다.
3. 🧠 권한 기반 분기 처리 – Role별로 UI를 나누자
✅ 대표적인 권한 구조
- admin: 관리자 페이지 전체 접근
- user: 마이페이지, 주문 등 사용자 콘텐츠
- guest: 로그인 이전의 방문자
📦 유저 정보 구조 예시
const user = {
id: 'abc123',
name: '홍길동',
role: 'admin'
};
📌 조건 렌더링 예시
{user?.role === 'admin' && (
<Link href="/admin">관리자 페이지</Link>
)}
✅ 권한별 페이지 보호
export async function getServerSideProps(context) {
const token = context.req.cookies.token;
const decoded = verifyToken(token);
if (decoded.role !== 'admin') {
return {
redirect: {
destination: '/',
permanent: false
}
};
}
return { props: {} };
}
➡️ 백엔드에서 role 정보를 담아주면, 프론트에서 다양한 UI/라우팅 분기가 가능합니다.
4. 🧱 역할 기반 레이아웃/네비게이션 구성
📦 메뉴 분기 처리 예시
const userMenu = [
{ name: '마이페이지', href: '/mypage', role: 'user' },
{ name: '주문내역', href: '/orders', role: 'user' },
{ name: '회원관리', href: '/admin/users', role: 'admin' }
];
<nav>
{userMenu
.filter(item => item.role === user.role)
.map(menu => (
<Link key={menu.href} href={menu.href}>{menu.name}</Link>
))}
</nav>
✅ 팀 협업 시 팁
- route-level guard는 미들웨어
- UI-level guard는 user.role 조건
- 페이지 안에서 데이터 접근 권한도 한 번 더 체크
5. 🎯 실전 설계 패턴 – 인증/권한 통합 관리 구조
📦 권장 구조 예시
/middleware.ts → 라우팅 보호
/src/store/auth.ts → user 상태 저장
/src/lib/token.ts → decodeToken, getUserRole
/src/components/AuthGuard.tsx → 고차 컴포넌트 방식 접근 제어
✅ 고차 컴포넌트 방식 예시
const withAuth = (WrappedComponent, allowedRoles = []) => {
return function Guarded(props) {
const { user } = useAuth();
if (!user || !allowedRoles.includes(user.role)) {
return <p>접근 권한이 없습니다.</p>;
}
return <WrappedComponent {...props} />;
};
};
➡️ 컴포넌트 단위로도 권한 분기를 유연하게 설정할 수 있습니다.
6. ✅ UX 친화적인 접근 제어 – 사용자 입장에서 생각하자
✅ 문제 상황
- 페이지 진입 시 갑작스러운 리디렉션 → “왜 날 쫓아냈지?”
- 단순히 빈 화면 or 콘솔 에러
📌 UX 개선 포인트
- 권한 부족 시 → 명확한 안내 메시지 제공
- 리디렉션 전 → 잠깐 로딩 or 전환 메시지 보여주기
- 403 에러 전용 페이지 구성
📦 예시: 403 페이지 구성
// pages/403.tsx
export default function Forbidden() {
return (
<div style={{ padding: '2rem', textAlign: 'center' }}>
<h2>⛔ 접근 권한이 없습니다.</h2>
<p>이 페이지는 관리자 전용입니다.</p>
<a href="/">홈으로 돌아가기</a>
</div>
);
}
📦 middleware에서 redirect
if (token && userRole !== 'admin' && pathname.startsWith('/admin')) {
return NextResponse.redirect(new URL('/403', req.url));
}
7. ❗ 에러 발생 시 대처 방식
✅ 클라이언트 단
- API 에러: toast or inline 메시지
- 권한 오류: 전용 메시지 + redirect or fallback UI
✅ 서버 단
- SSR에서 인증 실패 시 →
redirect
ornotFound
- 백엔드에서
403
응답 → 프론트에서 감지 후 처리
➡️ 모든 에러는 사용자가 명확하게 인지할 수 있게 안내해야 합니다.
8. 📋 접근 제어 & 권한 분기 체크리스트
🛡️ 보안 + UX를 모두 고려한 설계 포인트
- 로그인 여부 → SSR / 미들웨어로 제어
- 권한(Role)에 따라 메뉴/페이지/UI 분기
- 백엔드의 권한 검증도 반드시 함께 구현
- 403, 401 페이지 구성
- 권한 부족 시 사용자 친화적 안내 제공
📦 추천 구조
/middleware.ts
/src/pages/403.tsx
/src/store/auth.ts
/src/components/AuthGuard.tsx
긴 글 읽어주셔서 감사합니다! 공감, 댓글, 공유는 다음 글 제작에 큰 힘이 됩니다 🙌
반응형