안녕하세요! Nuxt.js 시리즈의 12번째 포스팅입니다.. 지난 번에는 플러그인과 유틸리티에 대해 알아보았는데요, 이번 시간에는 Nuxt.js의 강력한 기능 중 하나인 미들웨어(Middleware)와 라우트 가드에 대해 자세히 알아보겠습니다.
미들웨어는 페이지나 레이아웃이 렌더링되기 전에 실행되는 함수로, 사용자 인증 확인, 데이터 사전 로드, 리다이렉션 처리 등 다양한 상황에서 활용할 수 있습니다. 이를 통해 더 안전하고 유연한 애플리케이션을 구축할 수 있습니다.

1. 미들웨어의 개념과 종류
Nuxt.js에서 미들웨어는 크게 세 가지 유형으로 나눌 수 있습니다:
- 전역 미들웨어: 모든 라우트에 적용되는 미들웨어
- 레이아웃 미들웨어: 특정 레이아웃에 적용되는 미들웨어
- 페이지 미들웨어: 특정 페이지에만 적용되는 미들웨어
미들웨어는 서버 사이드와 클라이언트 사이드 모두에서 실행될 수 있으며, 페이지 이동 시 항상 미들웨어가 먼저 실행된 후 페이지 컴포넌트가 로드됩니다.
2. 미들웨어 생성 및 등록하기
Nuxt.js에서 미들웨어를 생성하려면 프로젝트 루트의 middleware 디렉토리에 JavaScript 파일을 생성하면 됩니다. 간단한 인증 미들웨어를 만들어 보겠습니다:
// middleware/auth.js
export default function ({ store, redirect }) {
// 사용자가 인증되지 않은 경우
if (!store.state.authenticated) {
return redirect('/login')
}
}
이 미들웨어는 스토어에서 인증 상태를 확인하고, 인증되지 않은 사용자를 로그인 페이지로 리다이렉트합니다.
3. 미들웨어 적용 방법
3.1 전역 미들웨어 적용
모든 페이지에 미들웨어를 적용하려면 nuxt.config.js 파일에 다음과 같이 설정합니다:
// nuxt.config.js
export default {
router: {
middleware: 'auth'
}
}
3.2 레이아웃에 미들웨어 적용
특정 레이아웃에만 미들웨어를 적용하려면 레이아웃 파일에서 다음과 같이 설정합니다:
// layouts/admin.vue
<template>
<div>
<Navbar />
<Nuxt />
<Footer />
</div>
</template>
<script>
export default {
middleware: 'admin-auth'
}
</script>
3.3 페이지에 미들웨어 적용
특정 페이지에만 미들웨어를 적용하려면 페이지 컴포넌트에서 다음과 같이 설정합니다:
// pages/dashboard.vue
<template>
<div>
<h1>대시보드</h1>
<!-- 대시보드 내용 -->
</div>
</template>
<script>
export default {
middleware: 'auth'
}
</script>
여러 미들웨어를 적용하려면 배열 형태로 지정할 수 있습니다:
<script>
export default {
middleware: ['auth', 'stats']
}
</script>4. 익명 미들웨어
파일로 분리하지 않고 컴포넌트 내에서 직접 미들웨어를 정의할 수도 있습니다:
// pages/secret.vue
<script>
export default {
middleware({ store, redirect }) {
if (!store.state.authenticated) {
return redirect('/login')
}
}
}
</script>이 방식은 특정 페이지에만 사용되는 간단한 미들웨어를 정의할 때 유용합니다.
5. 미들웨어 컨텍스트
미들웨어 함수는 Nuxt 컨텍스트 객체를 인자로 받습니다. 이 객체를 통해 다양한 Nuxt 기능에 접근할 수 있습니다:
export default function (context) {
// context는 다음 속성들을 포함합니다:
const {
app, // Nuxt 앱 인스턴스
store, // Vuex 스토어
route, // 현재 라우트
params, // 라우트 파라미터
query, // URL 쿼리 파라미터
redirect, // 리다이렉션 함수
error, // 에러 페이지 표시 함수
$axios, // axios 인스턴스 (설치된 경우)
req, // HTTP 요청 객체 (서버 사이드만)
res // HTTP 응답 객체 (서버 사이드만)
} = context
// 미들웨어 로직 작성
}
6. 실전 예제: 인증 시스템 구현
실제 프로젝트에서 미들웨어를 활용한 인증 시스템을 구현해 보겠습니다:
// middleware/auth.js
export default function ({ store, redirect, route }) {
// 인증이 필요한 페이지 경로 패턴
const authRequiredRoutes = ['/dashboard', '/profile', '/settings']
// 현재 경로가 인증이 필요한 페이지인지 확인
const requiresAuth = authRequiredRoutes.some(path => route.path.startsWith(path))
// 인증이 필요한 페이지인데 로그인하지 않은 경우
if (requiresAuth && !store.state.auth.loggedIn) {
// 로그인 후 돌아올 URL을 쿼리 파라미터로 전달
return redirect(`/login?redirect=${route.fullPath}`)
}
// 이미 로그인한 사용자가 로그인/회원가입 페이지에 접근하는 경우
if (route.path === '/login' || route.path === '/register') {
if (store.state.auth.loggedIn) {
return redirect('/dashboard')
}
}
}
이 미들웨어는 전역으로 등록하여 모든 페이지에 적용할 수 있습니다.
7. 역할 기반 접근 제어(RBAC)
사용자 역할에 따른 접근 제어를 구현하는 미들웨어를 만들어 보겠습니다:
// middleware/role.js
export default function ({ store, redirect, route }) {
// 관리자만 접근 가능한 페이지
const adminRoutes = ['/admin', '/manage-users']
// 현재 경로가 관리자 페이지인지 확인
const requiresAdmin = adminRoutes.some(path => route.path.startsWith(path))
// 관리자 페이지인데 관리자가 아닌 경우
if (requiresAdmin && store.state.auth.user.role !== 'admin') {
return redirect('/unauthorized')
}
}
8. 동적 레이아웃 할당
미들웨어를 사용하여 페이지에 동적으로 레이아웃을 할당할 수 있습니다:
// middleware/layout.js
export default function ({ store, route, app }) {
// 경로에 따라 레이아웃 결정
if (route.path.startsWith('/admin')) {
app.context.layout = 'admin'
} else if (route.path.startsWith('/blog')) {
app.context.layout = 'blog'
} else {
app.context.layout = 'default'
}
}
이 미들웨어를 전역으로 등록하면 경로에 따라 자동으로 적절한 레이아웃이 적용됩니다.
9. 성능 고려사항
미들웨어를 사용할 때 고려해야 할 성능 관련 사항들입니다:
- 미들웨어는 페이지 로드 전에 실행되므로, 무거운 작업은 피하는 것이 좋습니다.
- 비동기 작업이 필요한 경우 async/await 또는 Promise를 사용할 수 있습니다.
- 여러 미들웨어가 등록된 경우 순서대로 실행되므로, 순서를 고려해야 합니다.
10. 비동기 미들웨어
미들웨어에서 비동기 작업을 처리하는 방법을 알아보겠습니다:
// middleware/fetch-data.js
export default async function ({ store, route }) {
// 페이지 렌더링 전에 필요한 데이터 미리 로드
try {
await store.dispatch('fetchPageData', route.params.id)
} catch (error) {
console.error('데이터 로드 실패:', error)
}
}
11. 라우트 가드와의 비교
Vue Router의 라우트 가드와 Nuxt 미들웨어는 유사한 기능을 제공하지만, 몇 가지 차이점이 있습니다:
- Nuxt 미들웨어는 서버 사이드와 클라이언트 사이드 모두에서 실행됩니다.
- Vue Router 가드는 클라이언트 사이드에서만 실행됩니다.
- Nuxt 미들웨어는 Nuxt 컨텍스트 객체에 접근할 수 있어 더 많은 기능을 활용할 수 있습니다.
Nuxt에서도 Vue Router의 라우트 가드를 사용할 수 있습니다:
// pages/profile.vue
<script>
export default {
beforeRouteEnter(to, from, next) {
// 이 가드는 컴포넌트가 생성되기 전에 호출됩니다.
// 따라서 'this'에 접근할 수 없습니다.
next(vm => {
// vm을 통해 컴포넌트 인스턴스에 접근할 수 있습니다.
})
},
beforeRouteUpdate(to, from, next) {
// 이 가드는 현재 라우트가 변경될 때 호출됩니다.
// 'this'에 접근할 수 있습니다.
next()
},
beforeRouteLeave(to, from, next) {
// 이 가드는 현재 라우트에서 떠날 때 호출됩니다.
// 사용자가 저장하지 않은 변경사항을 두고 떠나려 할 때 유용합니다.
if (this.hasUnsavedChanges) {
if (!confirm('저장되지 않은 변경사항이 있습니다. 정말 떠나시겠습니까?')) {
return next(false)
}
}
next()
}
}
</script>
12. 실제 프로젝트에서의 미들웨어 구조화
대규모 프로젝트에서는 미들웨어를 체계적으로 구성하는 것이 중요합니다:
// middleware/index.js
import auth from './auth'
import role from './role'
import analytics from './analytics'
export default {
auth,
role,
analytics
}
이렇게 구성하면 미들웨어를 모듈화하고 필요에 따라 조합하여 사용할 수 있습니다.
마무리
이번 포스팅에서는 Nuxt.js의 미들웨어와 라우트 가드에 대해 알아보았습니다. 미들웨어는 페이지 렌더링 전에 실행되는 함수로, 인증 처리, 데이터 사전 로드, 동적 레이아웃 할당 등 다양한 용도로 활용할 수 있습니다. 이를 통해 더 안전하고 유연한 웹 애플리케이션을 구축할 수 있습니다.
미들웨어를 적절히 활용하면 코드의 재사용성을 높이고 애플리케이션의 보안을 강화할 수 있습니다. 특히 인증이 필요한 페이지나 특정 역할만 접근 가능한 페이지를 구현할 때 매우 유용합니다.
다음 포스팅 예고
다음 13회차에서는 Nuxt Content를 활용한 콘텐츠 중심 사이트 제작에 대해 알아보겠습니다. Markdown 파일을 기반으로 블로그나 문서 사이트를 쉽게 제작하는 방법, content 디렉토리 활용법, 쿼리 빌더 사용법, 그리고 컴포넌트 내에서 Markdown을 렌더링하는 방법 등을 자세히 다룰 예정입니다. 콘텐츠 중심의 웹사이트를 효율적으로 구축하고 싶으신 분들에게 매우 유용한 내용이 될 것입니다.






답글 남기기