사용자 역할 기반 접근 제어
사용자 역할 기반 접근 제어(RBAC)는 애플리케이션의 보안을 강화하고 사용자별로 다른 기능을 제공하는 데 중요한 역할을 합니다.
이 절에서는 Next.js 애플리케이션에서 RBAC를 구현하는 방법을 살펴보겠습니다.
사용자 역할 정의 및 저장
먼저, 사용자 역할을 정의하고 저장하는 방법을 알아보겠습니다.
일반적으로 사용자 역할은 데이터베이스에 저장되며, NextAuth.js의 세션에 포함시켜 사용할 수 있습니다.
- 데이터베이스 스키마 예시
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255),
role ENUM('admin', 'user', 'guest') DEFAULT 'user'
);
- NextAuth.js 설정에서 역할 정보 포함
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
const handler = NextAuth({
providers: [
// 프로바이더 설정...
],
callbacks: {
async jwt({ token, user }) {
if (user) {
token.role = user.role;
}
return token;
},
async session({ session, token }) {
session.user.role = token.role;
return session;
},
},
});
export { handler as GET, handler as POST };
서버 사이드에서의 역할 기반 접근 제어
서버 사이드에서 역할 기반 접근 제어를 구현하는 방법을 알아보겠습니다.
- 미들웨어를 사용한 라우트 보호
import { NextResponse } from 'next/server'
import { getToken } from 'next-auth/jwt'
export async function middleware(req) {
const token = await getToken({ req, secret: process.env.JWT_SECRET })
if (req.nextUrl.pathname.startsWith('/admin')) {
if (token?.role !== 'admin') {
return NextResponse.redirect(new URL('/unauthorized', req.url))
}
}
return NextResponse.next()
}
- API 라우트에서의 역할 확인
import { getServerSession } from "next-auth/next"
import { authOptions } from "../auth/[...nextauth]/route"
export async function GET(req) {
const session = await getServerSession(authOptions)
if (!session || session.user.role !== 'admin') {
return new Response("Unauthorized", { status: 401 })
}
// 관리자용 로직
return new Response("Admin only content", { status: 200 })
}
CSR에서의 역할 기반 접근 제어
클라이언트 사이드에서도 역할에 따른 UI 렌더링과 접근 제어를 구현할 수 있습니다.
- 훅을 사용한 역할 확인
import { useSession } from 'next-auth/react'
export function useRole() {
const { data: session } = useSession()
return session?.user?.role
}
- 컴포넌트 수준의 조건부 렌더링
import { useRole } from '../hooks/useRole'
function AdminOnlyComponent() {
const role = useRole()
if (role !== 'admin') {
return null
}
return <div>관리자용 컨텐츠</div>
}
- 고차 컴포넌트(HOC)를 사용한 역할 기반 접근 제어
function withRoleAccess(WrappedComponent, allowedRoles) {
return function WithRoleAccess(props) {
const role = useRole()
if (!allowedRoles.includes(role)) {
return <div>접근 권한이 없습니다.</div>
}
return <WrappedComponent {...props} />
}
}
const AdminPage = withRoleAccess(AdminDashboard, ['admin'])
API 라우트와의 연관성
11장에서 다룰 API 라우트와 역할 기반 접근 제어는 밀접하게 연관됩니다
API 라우트에서 사용자의 역할을 확인하여 특정 작업의 수행 여부를 결정할 수 있습니다.
예를 들어, 관리자만 사용자 정보를 수정할 수 있는 API 엔드포인트를 만들 수 있습니다.
import { getServerSession } from "next-auth/next"
import { authOptions } from "../../auth/[...nextauth]/route"
export async function PUT(req, { params }) {
const session = await getServerSession(authOptions)
if (!session || session.user.role !== 'admin') {
return new Response("Unauthorized", { status: 401 })
}
// 사용자 정보 수정 로직
// ...
return new Response("User updated", { status: 200 })
}
실습 : 역할별 대시보드 구현
관리자, 일반 사용자, 게스트 역할에 따라 다른 기능을 제공하는 대시보드 페이지를 구현해보겠습니다.
- 대시보드 컴포넌트 생성
'use client'
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'
export default function Dashboard() {
const { data: session, status } = useSession()
const router = useRouter()
if (status === 'loading') {
return <div>Loading...</div>
}
if (!session) {
router.push('/login')
return null
}
const role = session.user.role
return (
<div>
<h1>Dashboard</h1>
{role === 'admin' && <AdminDashboard />}
{role === 'user' && <UserDashboard />}
{role === 'guest' && <GuestDashboard />}
</div>
)
}
function AdminDashboard() {
return (
<div>
<h2>Admin Dashboard</h2>
<ul>
<li>사용자 관리</li>
<li>시스템 설정</li>
<li>로그 분석</li>
</ul>
</div>
)
}
function UserDashboard() {
return (
<div>
<h2>User Dashboard</h2>
<ul>
<li>프로필 수정</li>
<li>내 게시물</li>
<li>메시지 확인</li>
</ul>
</div>
)
}
function GuestDashboard() {
return (
<div>
<h2>Guest Dashboard</h2>
<p>제한된 기능만 사용 가능합니다. 더 많은 기능을 이용하려면 회원가입을 해주세요.</p>
<ul>
<li>공개 게시물 보기</li>
<li>회원가입</li>
</ul>
</div>
)
}
- 네비게이션 컴포넌트에 역할별 메뉴 추가
'use client'
import Link from 'next/link'
import { useSession } from 'next-auth/react'
export default function Navigation() {
const { data: session } = useSession()
return (
<nav>
<Link href="/">Home</Link>
<Link href="/dashboard">Dashboard</Link>
{session?.user.role === 'admin' && <Link href="/admin">Admin</Link>}
{session?.user.role === 'user' && <Link href="/profile">Profile</Link>}
{!session && <Link href="/login">Login</Link>}
</nav>
)
}
이 실습을 통해 사용자 역할에 따라 다른 대시보드 내용과 네비게이션 메뉴를 제공하는 방법을 익힐 수 있습니다.
이는 실제 애플리케이션에서 자주 사용되는 패턴으로, 사용자별로 맞춤화된 경험을 제공하는 데 도움이 됩니다.
Next.js에서의 사용자 역할 기반 접근 제어 구현은 애플리케이션의 보안을 강화하고 사용자 경험을 개선하는 중요한 요소입니다.
서버 사이드와 클라이언트 사이드에서 적절히 역할을 확인하고 접근을 제어함으로써, 안전하고 효율적인 애플리케이션을 구축할 수 있습니다.