跳转至内容

页面保护

NuxtAuth 提供了不同的页面保护方法

  • 全局中间件:保护所有页面,可手动排除例外
  • 本地中间件:保护特定页面
  • 自定义中间件:创建您自己的中间件

全局中间件

要在您的应用上启用全局中间件,您可以在 nuxt.config.ts 中配置中间件。

ts
export default defineNuxtConfig({
  modules: ['@sidebase/nuxt-auth'],
  auth: {
    globalAppMiddleware: true
  }
})

如果您想进一步自定义全局中间件,您可以将配置对象传递给 globalAppMiddleware。请参阅此处的 API 参考。

禁用全局中间件

如果全局中间件被禁用,您可以手动将中间件添加到各个页面。这仅在全局中间件被禁用时可用,否则您会收到类似于 Error: Unknown route middleware: 'auth' 的错误。这是因为 auth 中间件是全局添加的,不能用作本地的、页面特定的中间件。

vue
<script lang="ts" setup>
definePageMeta({
  middleware: 'sidebase-auth'
})
</script>

<template>
  Only I am protected!
</template>

本地中间件

要在单个页面上本地启用或禁用中间件,您可以使用 definePageMeta 宏来为单个页面设置身份验证元数据。

vue
<script setup lang="ts">
definePageMeta({
  auth: false
})
</script>

<template>
  I am not protected anymore!
</template>

中间件选项

auth 可以是布尔值或包含更多中间件配置的对象。

vue
<script setup lang="ts">
definePageMeta({
  auth: {
    unauthenticatedOnly: false,
    navigateUnauthenticatedTo: '/auth/signin'
  }
})
</script>

<template>
  I am protected with a custom redirect!
</template>

unauthenticatedOnly

是否仅允许未经身份验证的用户访问此页面。已通过身份验证的用户将被重定向到 / 或 navigateAuthenticatedTo 中指定的路由。

如果您想让所有人都能看到该页面,请设置 auth: false (参见 本地中间件)。

警告

0.9.4 版本开始,此选项是必需的,以防止歧义(相关问题)。请确保您设置了它,否则访客模式将默认启用 —— 您的访客将能够看到该页面,但您已通过身份验证的用户将被重定向走。

如果 unauthenticatedOnly 设置为 true,则将已通过身份验证的用户重定向到哪里。

如果此页面受到保护,则将未经身份验证的用户重定向到哪里。

访客模式

您可以使用 NuxtAuth 设置仅在用户未登录时才可访问的页面。这有时被称为“访客模式”。此类页面的行为如下:

  • 已登录用户访问页面 -> 重定向到另一个(可能是受保护的)页面,
  • 已登出用户访问页面 -> 他们被允许停留并查看

这种行为对于您不希望已登录用户访问的登录页面非常有用:为什么他们应该再次经历登录流程?

vue
<script setup lang="ts">
definePageMeta({
  auth: {
    unauthenticatedOnly: true,
    navigateAuthenticatedTo: '/profile'
  }
})
</script>

<template>
  I can only be viewed as a guest!
</template>

自定义中间件

您可以创建自己的应用侧中间件,以便实现自定义的、更高级的身份验证逻辑。

警告

创建自定义中间件是一个高级的、实验性的选项,如果您不熟悉高级的 Nuxt 3 概念,可能会导致意外或不期望的行为。

要实现您的自定义中间件

  • 创建一个应用侧中间件,它可以全局应用或被命名(更多信息请参阅 Nuxt 文档)
  • 基于 useAuth 向其添加逻辑

在添加逻辑时,您需要注意在调用其他 async composable 函数时。这可能会导致 Nuxt 中的 context 问题,请参阅此处的解释。为了避免这些问题,您需要:

  • 在等待其他 composables 时,使用未文档化的 callWithNuxt 实用程序
  • 尽可能返回一个 async 函数而不是等待它,以避免 callWithNuxt
ts
// file: ~/middleware/authentication.global.ts
export default defineNuxtRouteMiddleware((to) => {
  const { status, signIn } = useAuth()

  // Return immediately if user is already authenticated
  if (status.value === 'authenticated') {
    return
  }

  /**
   * We cannot directly call and/or return `signIn` here as `signIn` uses async composables under the hood, leading to "nuxt instance undefined errors", see https://github.com/nuxt/framework/issues/5740#issuecomment-1229197529
   *
   * So to avoid calling it, we return it immediately.
   */
  return signIn(undefined, { callbackUrl: to.path }) as ReturnType<typeof navigateTo>
})
ts
// file: ~/middleware/authentication.global.ts
import { useNuxtApp } from '#imports'
import { callWithNuxt } from '#app/nuxt'

export default defineNuxtRouteMiddleware((to) => {
  // It's important to do this as early as possible
  const nuxtApp = useNuxtApp()

  const { status, signIn } = useAuth()

  // Return immediately if user is already authenticated
  if (status.value === 'authenticated') {
    return
  }

  /**
   * We cannot directly call and/or return `signIn` here as `signIn` uses async composables under the hood, leading to "nuxt instance undefined errors", see https://github.com/nuxt/framework/issues/5740#issuecomment-1229197529
   *
   * So to avoid calling it, we call it via `callWithNuxt`.
   */
  await callWithNuxt(nuxtApp, signIn, [undefined, { callbackUrl: to.path }])
})

在 MIT 许可证下发布。