基础篇二 Nuxt4 路由守卫:页面访问控制

文章目录

有些页面不是谁都能访问的。后台管理只有管理员能进,个人中心需要登录才能看,会员内容要付费才能解锁......这些都是页面访问控制的场景。Nuxt 的中间件系统就是来解决这些问题的。

一、什么是路由守卫

路由守卫就是导航过程中的"关卡":

  1. 用户点击链接
  2. 触发路由守卫(关卡检查)
  3. 检查通过 → 放行
  4. 检查不通过 → 重定向或拦截

Nuxt 用中间件来实现路由守卫,比 Vue Router 的方式更简洁。

二、定义中间件

中间件放在 middleware 目录。创建一个登录检查中间件:

ts 复制代码
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const token = useCookie('token')
  
  // 未登录,跳转到登录页
  if (!token.value) {
    return navigateTo('/login')
  }
})

在页面中使用:

vue 复制代码
<script setup lang="ts">
definePageMeta({
  middleware: 'auth'  // 使用 auth 中间件
})
</script>

<template>
  <div>
    <h1>个人中心</h1>
    <p>只有登录用户能看到</p>
  </div>
</template>

三、全局中间件

想让中间件对所有页面生效,文件名加 .global 后缀:

ts 复制代码
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  // 所有页面都会经过这里
  console.log('导航到:', to.path)
})

典型场景:全局登录状态检查

ts 复制代码
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const token = useCookie('token')
  const publicPages = ['/', '/login', '/register']
  
  // 公开页面直接放行
  if (publicPages.includes(to.path)) {
    return
  }
  
  // 非公开页面需要登录
  if (!token.value) {
    return navigateTo('/login')
  }
})

四、多个中间件

页面可以同时使用多个中间件:

vue 复制代码
<script setup lang="ts">
definePageMeta({
  middleware: [
    'auth',      // 先检查登录
    'admin'      // 再检查管理员权限
  ]
})
</script>

中间件按数组顺序执行,任何一个返回重定向就会中断后续流程。

五、中间件传参

中间件可以接收参数:

ts 复制代码
// middleware/role.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const requiredRole = to.meta.role as string
  const userRole = useCookie('role').value
  
  if (requiredRole && userRole !== requiredRole) {
    return navigateTo('/403')
  }
})

页面中定义需要的角色:

vue 复制代码
<script setup lang="ts">
definePageMeta({
  middleware: 'role',
  meta: {
    role: 'admin'  // 需要管理员角色
  }
})
</script>

六、重定向选项

navigateTo 支持多种选项:

ts 复制代码
// 外部链接
return navigateTo('https://google.com', { external: true })

// 替换历史记录
return navigateTo('/login', { replace: true })

// 新窗口打开
return navigateTo('/report', { open: { target: '_blank' } })

// 保留查询参数
return navigateTo({
  path: '/login',
  query: { redirect: to.fullPath }  // 登录后跳回原页面
})

七、中止导航

不是所有情况都要重定向,有时候只需要中止:

ts 复制代码
export default defineNuxtRouteMiddleware((to, from) => {
  const confirmed = confirm('确定要离开吗?未保存的内容会丢失')
  
  if (!confirmed) {
    return abortNavigation()  // 中止导航,留在当前页
  }
  
  // 返回 undefined 或不返回就是放行
})

还可以传递错误信息:

ts 复制代码
export default defineNuxtRouteMiddleware((to, from) => {
  return abortNavigation(
    createError({
      statusCode: 403,
      message: '您没有权限访问此页面'
    })
  )
})

八、页面离开确认

表单页面常用,防止用户误操作丢失数据:

ts 复制代码
// middleware/unsaved-changes.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const hasUnsavedChanges = useState('unsavedChanges')
  
  if (hasUnsavedChanges.value) {
    const confirmed = confirm('有未保存的更改,确定要离开吗?')
    if (!confirmed) {
      return abortNavigation()
    }
    // 确认离开,重置状态
    hasUnsavedChanges.value = false
  }
})

页面中:

vue 复制代码
<script setup lang="ts">
const hasUnsavedChanges = useState('unsavedChanges')

// 表单数据变化时
watch(formData, () => {
  hasUnsavedChanges.value = true
}, { deep: true })

// 保存成功后
const save = async () => {
  await saveForm()
  hasUnsavedChanges.value = false
}

definePageMeta({
  middleware: 'unsaved-changes'
})
</script>

九、服务端中间件

中间件在 SSR 时也会执行。有些检查需要只在服务端进行:

ts 复制代码
export default defineNuxtRouteMiddleware(async (to, from) => {
  // 只在服务端执行
  if (process.server) {
    const event = useRequestEvent()
    const ip = getRequestIP(event)
    
    // IP 黑名单检查
    if (await isBlockedIP(ip)) {
      return navigateTo('/blocked')
    }
  }
})

十、中间件执行顺序

Nuxt 中间件执行顺序:

  1. 全局中间件(按字母排序)
  2. 页面定义的中间件(按定义顺序)
  3. 布局中间件(如果有)
ts 复制代码
// middleware/01-first.global.ts  - 先执行
// middleware/02-second.global.ts - 后执行

十一、调试中间件

开发时可以打印日志:

ts 复制代码
export default defineNuxtRouteMiddleware((to, from) => {
  console.log('From:', from.path)
  console.log('To:', to.path)
  console.log('Meta:', to.meta)
})

总结

路由守卫核心用法:

功能 实现方式
登录检查 middleware/auth.ts
全局守卫 文件名加 .global
多个守卫 middleware: ['auth', 'admin']
重定向 navigateTo('/path')
中止导航 abortNavigation()
传递错误 abortNavigation(createError(...))

路由守卫是权限控制的基础,下一篇我们聊聊组件进阶------插槽与事件传递。

相关文章

入门篇三:Nuxt4组件自动导入:写代码少敲一半字

入门篇二:Nuxt 4路由自动生成:告别手动配置路由的日子

延伸阅读

nuxt4完整系列,持续更新中。。,欢迎来逛逛


内容有帮助?点赞、收藏、关注三连!评论区等你 💪

相关推荐
brien919 分钟前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance34 分钟前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M41 分钟前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写43 分钟前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李44 分钟前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易1 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马1 小时前
前沿视界
前端
kyriewen1 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易2 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员
IT_陈寒2 小时前
Vue的这个响应式陷阱,差点让我加班到天亮
前端·人工智能·后端