Middleware
Bob descobriu que Alice poderia acessar diretamente o painel administrativo /admin sem nenhuma verificação de permissão. Charlie precisa de um guardião de rota — que redirecione automaticamente usuários não autenticados que tentam acessar a página de administração para a página de login, e impeça usuários comuns de acessar rotas administrativas. O sistema de middleware do Nuxt 3 é a solução.
1. O Que Você Vai Aprender
- Middleware global: middleware/auth.global.ts - Escopo global e ordem de execução
- Middleware nomeado: combinação de
definePageMetae um array de middleware - Middleware inline: Middleware leve definido diretamente dentro de uma página
- Middleware e SSR: Mecanismos de Dupla Execução e Middleware Somente no Cliente
- Guardião de Rota do Administrador do MegaShop + Verificação de Papel: Guia Prático
2. Uma História Real de um Administrador
(1) Ponto Crítico: Uma Vulnerabilidade Crítica Devido à Falta de Controle de Permissão
Alice digitou /admin no navegador e acessou o painel administrativo do MegaShop, onde podia ver todos os pedidos e dados de usuários. Bob, como administrador, descobriu que a interface que via era exatamente igual à de um usuário comum, sem nenhuma distinção. Charlie precisava urgentemente de controle de acesso em nível de rota.
(2) Solução com Middleware de Rota
No Nuxt 3, o middleware é executado antes de uma transição de rota e pode redirecionar ou bloquear o acesso:
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
if (!isAuthenticated()) return navigateTo('/login')
})
(3) Benefícios: Controle de Acesso em Nível de Rota
Alice não pode mais acessar /admin diretamente; se não estiver logada, é redirecionada automaticamente para a página de login. Os privilégios de administrador de Bob são aplicados em nível de rota.
3. Três Padrões de Middleware
(1) Ordem de Execução do Middleware
flowchart LR
A[Route Navigation] --> B[Global Middleware 1]
B --> C[Global Middleware 2]
C --> D[Named/Inline Middleware]
D --> E[Page Render]
D -->|abort| F[Redirect / Abort]
B -->|abort| F
C -->|abort| F
(2) Comparação dos Três Modelos
| Dimensão | Middleware Global | Middleware Nomeado | Middleware Inline |
|---|---|---|---|
| Nome do Arquivo | *.global.ts | *.ts (sem "global") | Sem arquivo |
| Escopo | Todas as Rotas | Páginas Específicas | Página Atual |
| Método de Definição | diretório middleware/ | diretório middleware/ | dentro de definePageMeta |
| Reusabilidade | ✅ Reuso automático | ✅ Referência em múltiplas páginas | ❌ Somente na página atual |
| Casos de Uso | Autenticação/Logging Global | Guarda Específica de Página | Verificação Simples Única |
4. Middleware Global
(1) ▶Exemplo: Middleware de Autenticação Global
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// Pular autenticação para páginas públicas
const publicPages = ['/', '/products', '/about', '/login', '/register']
if (publicPages.includes(to.path)) return
const token = useCookie('auth-token')
if (!token.value) {
return navigateTo(`/login?redirect=${to.path}`, { redirectCode: 302 })
}
})
Saída:
// Execução Bem-sucedida
(2) ▶Exemplo: Middleware de Log Global
// middleware/log.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
console.log(`Navegação: ${from.path} → ${to.path}`)
// Sem retorno = permitir navegação
})
Saída:
// Execução Bem-sucedida
01-auth.global.ts executa antes de 02-log.global.ts. Recomendamos usar um prefixo numérico para controlar a ordem.
5. Middleware Nomeado
(1) ▶Exemplo: Middleware de Papel de Administrador
// middleware/admin.ts
export default defineNuxtRouteMiddleware((to) => {
const user = useState('user')
if (!user.value) {
return navigateTo(`/login?redirect=${to.path}`)
}
if (user.value.role !== 'admin') {
// Usuário comum tentando acessar página de administração
throw createError({
statusCode: 403,
message: 'Access denied. Admin role required.'
})
}
})
Saída:
// Execução Bem-sucedida
(2) ▶Exemplo: Referenciando um middleware nomeado em uma página
<!-- pages/admin/index.vue -->
<template>
<div>
<h1>Admin Dashboard</h1>
<p>Welcome, Bob (Admin)</p>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: 'admin', // Referenciar middleware nomeado
layout: 'sidebar'
})
</script>
Saída:
// Execução Bem-sucedida
(3) ▶Exemplo: Combinando Múltiplos Middleware
<!-- pages/admin/settings.vue -->
<template>
<div>
<h1>Admin Settings</h1>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: ['auth', 'admin'], // Executar em ordem: auth → admin
layout: 'sidebar'
})
</script>
Saída:
// Execução Bem-sucedida
6. Middleware Inline
(1) ▶Exemplo: Definindo middleware dentro de uma página
<!-- pages/checkout.vue -->
<template>
<div>
<h1>Checkout</h1>
<p>Cart total: ${{ total }} USD</p>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: defineNuxtRouteMiddleware((to) => {
// Inline: verificar se o carrinho tem itens
const cart = useState<any[]>('cart')
if (cart.value.length === 0) {
return navigateTo('/cart')
}
})
})
const cart = useState<any[]>('cart')
const total = computed(() => cart.value.reduce((s, i) => s + i.price, 0))
</script>
Saída:
// Execução Bem-sucedida
(1) Escolhendo Entre Middleware Inline e Nomeado
| Cenário | Escolha | Motivo |
|---|---|---|
| Autenticação em todo o site | Global | Verificar toda rota |
| Rotas Administrativas | Nomeado | Compartilhado por Múltiplas Páginas Admin |
| Verificar se o carrinho não está vazio | Inline | Usar apenas na página de checkout |
| Área VIP | Nomeado | Pode ser usado em múltiplas páginas |
| Teste A/B de Divisão de Tráfego | Inline | Lógica Única |
7. Middleware e SSR
(1) Mecanismo de Dupla Execução SSR
flowchart TB
A[User navigates to /admin] --> B[Server: middleware executes]
B -->|redirect| C[Server sends redirect response]
B -->|allow| D[Server renders page]
D --> E[Client: middleware executes again]
E -->|redirect| F[Client-side redirect]
E -->|allow| G[Client hydrates page]
(1) ▶Exemplo: Middleware Somente no Cliente
// middleware/client-only.ts
export default defineNuxtRouteMiddleware((to) => {
// Pular no servidor - verificar apenas no cliente
if (import.meta.server) return
const localStorage = window.localStorage
const preferences = JSON.parse(localStorage.getItem('user-preferences') || '{}')
if (preferences.theme === 'dark') {
// Lógica somente no cliente usando APIs do navegador
document.documentElement.classList.add('dark')
}
})
Saída:
// Execução Bem-sucedida
(2) Considerações para Middleware SSR
| Problema | Causa | Solução |
|---|---|---|
| Middleware executa duas vezes | SSR e cliente executam uma vez cada | Comportamento esperado; garantir idempotência |
| Usando window/localStorage | SSR (sem ambiente de navegador) | Verificação com if (import.meta.client) |
| Cookies estão disponíveis no SSR | Requisições carregam cookies | Lidos usando useCookie |
| navigateTo no SSR | Retorna um redirecionamento 302 | Comportamento esperado |
| useState no middleware | ✅ Disponível | Adequado para verificar status de login |
8. Exemplo Completo: O Sistema de Guarda de Permissões do MegaShop
// middleware/01-auth.global.ts - Verificação global de autenticação
export default defineNuxtRouteMiddleware((to) => {
const publicPaths = ['/', '/products', '/products/**', '/about', '/login', '/register']
const isPublic = publicPaths.some(path => {
if (path.includes('')) return to.path.startsWith(path.replace('/', ''))
return path === to.path
})
if (isPublic) return
const token = useCookie('auth-token')
if (!token.value) {
return navigateTo(`/login?redirect=${encodeURIComponent(to.path)}`)
}
})
// middleware/admin.ts - Verificação de papel de administrador
export default defineNuxtRouteMiddleware((to) => {
const user = useCookie('user-data')
if (!user.value) {
return navigateTo('/login')
}
if ((user.value as any).role !== 'admin') {
throw createError({ statusCode: 403, message: 'Admin access required' })
}
})
<!-- pages/admin/products/index.vue -->
<template>
<div>
<h1>Product Management</h1>
<p>Manage 1 million products</p>
<!-- Interface CRUD de produtos administrativos -->
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: ['admin'],
layout: 'sidebar'
})
</script>
❓Perguntas Frequentes
definePageMeta.defineNuxtRouteMiddleware em si não suporta async. No entanto, você pode chamar APIs síncronas (como useCookie ou useState) dentro do middleware. Se precisar realizar validação assíncrona, é recomendável tratá-la em um plugin ou no método setup da página.createError for lançado no middleware?error.vue.useState ou a propriedade payload de NuxtApp. const nuxtApp = useNuxtApp() → nuxtApp.payload.xxx = data. O próximo middleware ou página pode acessá-lo.📖Resumo
- Três tipos de middleware: global (todas as rotas), nomeado (páginas específicas) e inline (página atual)
- O middleware global é executado em ordem alfabética pelo nome do arquivo; recomenda-se usar um prefixo numérico para controlar a ordem
- Múltiplos middleware nomeados podem ser combinados usando a referência do array
middlewareemdefinePageMeta - A dupla execução SSR é um comportamento esperado; a API do navegador deve ser protegida usando
import.meta.client - MegaShop implementa guarda de permissão completa usando autenticação global e um middleware admin nomeado
📝Exercícios
- Exercício Básico (Dificuldade: ⭐): Crie um middleware chamado
guest.tsque permita apenas usuários não autenticados acessar a página (usuários logados são redirecionados para a página inicial), e aplique-o à página/login. - Exercício Avançado (Dificuldade ⭐⭐): Implemente um sistema completo de autorização: verificação global de autenticação para login + verificação de papel para o usuário "admin"; a rota /admin/** é protegida.
- Desafio (Dificuldade: ⭐⭐⭐): Implemente a passagem de dados entre middleware — obtenha informações do usuário no middleware
authe armazene-as no payload doNuxtApp, depois leia-as diretamente no middlewareadminpara evitar requisições duplicadas.
---|



