news 2026/9/10 2:50:06

airi 前端鉴权指南:用 VueUse useAuth 在 Vue 3 中响应式绑定 Firebase Auth 登录状态

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
airi 前端鉴权指南:用 VueUse useAuth 在 Vue 3 中响应式绑定 Firebase Auth 登录状态

airi 前端鉴权指南:用 VueUse useAuth 在 Vue 3 中响应式绑定 Firebase Auth 登录状态

【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi

useAuth是 VueUse 官方 Firebase 集成(@vueuse/firebase)提供的响应式鉴权绑定,它把 Firebase Auth 的登录状态封装成userisAuthenticated两个响应式值,让 Vue 组件可以声明式地响应登录、登出与令牌刷新事件。本文以 airi 仓库中 vueuse-functions 技能库 的 useAuth 参考文档 为主体,完整讲解其用法、返回值、底层监听机制与类型声明,并结合 airi 仓库自研的响应式鉴权实现(useAuthStore)做源码级对照,帮助你掌握"用响应式状态驱动 UI 鉴权"这一通用设计模式。

一、技能定位:useAuth 在 vueuse-functions 中的角色

在 airi 仓库的.agents/skills/vueuse-functions/技能库中,所有 VueUse 组合式函数按功能分类维护了各自的参考文档,useAuth被归类在@Firebase分组下,与该分组的 useFirestore(响应式 Firestore 绑定)、useRTDB(响应式 Realtime Database 绑定)并列,三者同属@vueuse/firebase集成包。

根据 SKILL.md 中的调用规则(Invocation)标注,useAuth的调用级别为EXTERNAL,即:仅当用户已经安装了@vueuse/firebasefirebase外部依赖时才应当使用;否则需要先评估是否真正需要该依赖,再决定是否安装。这是技能库对"外部集成类组合式函数"的通用约束——避免为了一句便利的响应式封装而引入整个 SDK。

### @Firebase | 函数 | 描述 | Invocation | |--------------|-----------------------------------|------------| | useAuth | Reactive Firebase Auth binding | EXTERNAL | | useFirestore | Reactive Firestore binding | EXTERNAL | | useRTDB | Reactive Firebase Realtime Database binding | EXTERNAL |

从类型声明来看,useAuth被标注了@__NO_SIDE_EFFECTS__,这是一个面向打包器的 tree-shaking 注解,表示调用该函数本身不会产生模块级副作用,从而允许构建工具在未使用该导入时安全地将其从产物中剔除。

二、核心用法:把 Firebase Auth 状态变成响应式数据

useAuth的使用方式非常简洁:它接收一个由 Firebase SDK 创建的Auth实例,返回响应式的userisAuthenticated。参考文档给出了一个可直接运行的最小示例(Vue 3<script setup>语法):

<script setup lang="ts"> import { useAuth } from '@vueuse/firebase/useAuth' import { initializeApp } from 'firebase/app' import { getAuth, GoogleAuthProvider, signInWithPopup } from 'firebase/auth' const app = initializeApp({ /* config */ }) const auth = getAuth(app) const { isAuthenticated, user } = useAuth(auth) const signIn = () => signInWithPopup(auth, new GoogleAuthProvider()) </script> <template> <pre v-if="isAuthenticated">{{ user }}</pre> <div v-else> <button @click="signIn"> Sign In with Google </button> </div> </template>

拆解这个示例,可以得到完整的调用链:

  1. 初始化 Firebase 应用initializeApp({ /* config */ })需要传入你的 Firebase 项目配置(apiKey、authDomain 等),通常在应用入口处完成一次,再通过模块导出复用;
  2. 获取 Auth 实例getAuth(app)从应用中取出认证实例,它是后续所有鉴权操作的入口;
  3. 响应式绑定useAuth(auth)返回的isAuthenticateduser会随认证状态自动更新,模板中无需手动刷新;
  4. 发起登录signInWithPopup(auth, new GoogleAuthProvider())是 Firebase 提供的弹出式 Google 登录方法——注意登录动作本身仍由 Firebase SDK 驱动,useAuth只负责"感知"并传播状态变化。

在真实业务中,你通常还需要处理登出与用户信息展示。可以在同一组件中直接组合 Firebase 原生的signOutuseAuth的返回值,形成完整的登录生命周期:

<script setup lang="ts"> import { useAuth } from '@vueuse/firebase/useAuth' import { getAuth, signInWithPopup, signOut, GoogleAuthProvider } from 'firebase/auth' const auth = getAuth() const { isAuthenticated, user } = useAuth(auth) const signIn = () => signInWithPopup(auth, new GoogleAuthProvider()) const signOutUser = () => signOut(auth) </script> <template> <div v-if="isAuthenticated && user"> <p>{{ user.displayName ?? user.email }}</p> <button @click="signOutUser">Sign Out</button> </div> <button v-else @click="signIn">Sign In</button> </template>

user是可空引用(null表示未登录),因此模板中与v-if组合使用时需要做空值守卫;而isAuthenticated是布尔型计算属性,可直接用于路由守卫、导航栏按钮、页面拦截等场景的条件分支。

三、返回值详解

参考文档用一张表明确了useAuth的两个返回值,其类型与语义如下:

名称类型说明
userRef<User \| null>当前 Firebase 用户对象;未认证时为null
isAuthenticatedComputedRef<boolean>当前是否处于已认证状态

需要强调两个关键点:

  • userRefisAuthenticatedComputedRef。在<script setup>顶层解构后,模板中可直接使用(Vue 会自动解包);在 JS 逻辑中则需通过.value访问,或借助storeToRefstoRefs等工具维持响应式。
  • isAuthenticated是从user派生的,即user.value !== null。这意味着它天然与user保持一致,不存在"user 已有值但 isAuthenticated 仍为 false"的状态撕裂问题。

四、底层原理:onIdTokenChanged 监听器

useAuth之所以能做到"状态自动更新",核心在于它内部注册了 Firebase Auth 的onIdTokenChanged监听器。参考文档明确指出:

The composable automatically updates when the user's ID token changes (including sign-in, sign-out, and token refresh events) using Firebase'sonIdTokenChangedlistener.

onIdTokenChanged是 Firebase Auth 提供的状态监听 API,它会在以下事件发生时触发回调:

  • 登录(sign-in):包括signInWithPopupsignInWithRedirectsignInWithEmailAndPassword等所有登录方式完成之后;
  • 登出(sign-out):调用signOut后用户对象变为null
  • ID Token 刷新(token refresh):Firebase 会周期性地自动刷新用户的 ID Token(默认约每小时),此时也会触发监听——这正是useAuth相比"只在登录/登出时手动更新一次"的朴素实现更可靠的原因:即使会话在后台被静默刷新,响应式状态也始终与真实认证态同步。

使用useAuth之后,组件无需自己管理监听器的注册与解绑——这正是 VueUse 组合式函数"依赖 Vue 组件作用域自动清理"的设计惯例(组件卸载时随 scope dispose 一并解除),避免了传统onAuthStateChanged手动注册/卸载容易造成的内存泄漏问题。

五、类型声明逐段解析

参考文档给出了useAuth的完整 TypeScript 类型声明,理解它能帮助你正确地消费user对象。整理后其签名结构为:

export declare function useAuth(auth: Auth): { isAuthenticated: ComputedRef<boolean> user: Ref<User | null> }

其中User是对 Firebase 用户模型的静态类型描述,包含以下关键字段与方法:

成员类型用途
uidstring用户唯一标识,跨会话稳定
email/displayName/phoneNumber/photoURLstring \| null用户的邮箱、显示名、电话、头像链接(可空)
emailVerifiedboolean邮箱是否已验证,常用于"未验证禁止访问"策略
isAnonymousboolean是否匿名用户(匿名登录场景)
metadata{ creationTime?, lastSignInTime? }账号创建时间与最近登录时间
providerData数组各登录提供方(Google、GitHub 等)对应的资料快照
refreshTokenstring刷新令牌,用于换取新的 ID Token
tenantIdstring \| null多租户(Firebase Identity Platform)场景下的租户 ID
delete()() => Promise<void>删除当前用户账号
getIdToken(forceRefresh?)() => Promise<string>获取(或强制刷新)ID Token,是携带 Bearer 请求头访问受保护 API 的常用方式
getIdTokenResult(forceRefresh?)() => Promise<IdTokenResult>获取 ID Token 及其声明信息
reload()() => Promise<void>重新加载用户资料(如邮箱验证后刷新状态)
toJSON()() => object序列化为纯对象

实际使用中,最常消费的是uidemaildisplayNamephotoURL(用于展示头像与昵称)与getIdToken()(用于向自己的后端接口传递凭证)。

六、源码级对照:airi 仓库的响应式鉴权实现

有趣的是,airi 仓库本身并未使用 Firebase Auth,而是采用了自研的OIDC + Better Auth鉴权栈——但它在设计上与useAuth遵循着完全相同的"响应式状态驱动 UI"哲学。对照阅读可以加深你对本主题的理解。

6.1 相同的响应式骨架:user + isAuthenticated

airi 的鉴权核心是 packages/stage-ui/src/stores/auth.ts 中的useAuthStore(Pinia store)。它暴露了与useAuth同构的状态对:

const user = ref<User | null>(null) const session = ref<Session | null>(null) const isAuthenticated = computed(() => !!user.value && !!session.value)

与 VueUseuseAuth一样:userRefisAuthenticated是派生的ComputedRef。只是 airi 的判定更严格——要求用户对象与服务端会话对象同时存在才视为已认证。

6.2 监听状态迁移:watch(isAuthenticated)

useAuth通过onIdTokenChanged回调感知状态变化;airi 则用 Vue 的watch监听isAuthenticated的翻转,并在翻转时执行认证/登出钩子(见 auth.ts#L369-L394):

watch(isAuthenticated, async (authenticated, wasAuthenticated) => { if (authenticated) { void updateCredits() needsLogin.value = false if (!wasAuthenticated) await dispatchHooks(authenticatedHooks, 'auth hook error') } else { credits.value = 0 if (wasAuthenticated) await dispatchHooks(logoutHooks, 'logout hook error') } }, { immediate: true })

这段实现展示了响应式鉴权的两个实用技巧:

  • { immediate: true }:store 初始化时立即执行一次,保证"注册钩子时若已登录则立刻触发"(对应 onAuthenticated 中的提前触发逻辑);
  • 钩子机制:用authenticatedHooks/logoutHooks数组注册回调,业务模块通过onAuthenticated/onLogout订阅登录/登出事件,解耦了"状态变化"与"副作用执行"。

6.3 状态消费的 UI 侧印证

在组件层,airi 的鉴权按钮同样把状态解构成响应式变量供模板消费。以 controls-island-auth-button.vue 为例:

const { isAuthenticated, user, needsLogin, credits } = storeToRefs(authStore)

这与useAuth示例中"解构出isAuthenticateduser,在模板中v-if分支渲染"的模式完全一致——响应式鉴权状态让 UI 的"登录前/登录后"切换变成纯粹的声明式渲染,无需手动管理任何中间状态。

6.4 更进一步的工程化:401 自动刷新

useAuth依赖 Firebase 自动刷新 ID Token;airi 则在 packages/stage-ui/src/libs/auth-fetch.ts 的authedFetch中实现了"401 → 单飞刷新令牌 → 重放请求"的安全网机制。它之所以需要这层兜底,正如代码注释所说明的:时钟偏移、挂起的标签页、刷新后的竞态都可能让过期的 Bearer Token 泄漏出去(auth-fetch.ts#L5-L19)。这个思路同样适用于 Firebase 场景——即使onIdTokenChanged会传播刷新事件,对后端请求仍建议在收到 401 时执行一次user.getIdToken(true)强制刷新后重试。

七、典型应用场景与注意事项

基于以上原理,useAuth最常见的落地场景包括:

  1. 导航栏登录态切换v-if="isAuthenticated"决定展示"用户头像/登出"还是"登录按钮",与 airi 中 HeaderAvatar.vue 的做法一致;
  2. 路由守卫与页面拦截:在路由前置守卫中读取isAuthenticated.value,未登录则重定向到登录页——airi 的 onboarding.vue 正是用watch([isAuthenticated, closeRequestId])实现登录引导的;
  3. 用户信息展示:解构user后读取displayNamephotoURLemail等字段渲染头像与昵称;
  4. 受保护 API 调用:用user.getIdToken()获取 ID Token 作为 Bearer 凭证请求后端。

使用时的注意事项:

  • usernull时访问其属性会报错,模板中务必用v-if/v-else分流或可选链(user?.displayName);
  • isAuthenticated是计算属性,不要直接对它赋值;需要手动重置状态时应通过signOut完成;
  • useAuth要求前置安装firebase@vueuse/firebase(EXTERNAL 调用级别),若项目尚未使用 Firebase,请先评估是否值得为响应式封装引入整套 SDK;
  • 当页面同时存在多个组件调用useAuth时,它们共享同一个Auth实例的监听结果,状态保持一致,不会出现互相覆盖的问题。

结语

useAuth以极小的 API 面(一个函数、两个返回值)解决了 Firebase 前端鉴权中最常见的痛点——登录状态的响应式同步。它的设计精髓在于:把"监听外部异步状态"这一样板逻辑封装进组合式函数,让组件只关心"状态是什么"而不用关心"状态怎么来的"。airi 仓库自研的useAuthStore虽然在技术上选择了 OIDC + Better Auth 而非 Firebase,但其user/isAuthenticated/watch(isAuthenticated)的结构与useAuth如出一辙,印证了这一模式在真实项目中的可迁移性。掌握useAuth,也就掌握了在任意 Vue 3 项目中搭建响应式鉴权层的通用范式。

参考文档:.agents/skills/vueuse-functions/references/useAuth.md | 技能索引:.agents/skills/vueuse-functions/SKILL.md | airi 对照实现:packages/stage-ui/src/stores/auth.ts

【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 2:47:24

CANN/ge GetKernelArgs API文档

GetKernelArgs 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFlow …

作者头像 李华
网站建设 2026/9/10 2:43:17

社区家政小程序开发公司排名,上门服务系统搭建

社区家政小程序开发公司排名&#xff0c;上门服务系统搭建当下社区上门家政服务行业持续升温&#xff0c;保洁养护、家电维修、居家护理、便民修缮等服务需求日益常态化。众多中小家政企业、社区服务站点都开始摒弃传统线下登记、公域平台入驻的运营模式&#xff0c;转向自主搭…

作者头像 李华
网站建设 2026/9/10 2:40:00

NILMTK实战:非侵入式负荷监测工具包的环境配置与数据分解

简介&#xff1a;面向非侵入式负荷监测&#xff08;NILM&#xff09;研究者的完整可运行项目包&#xff0c;基于REDD低频数据集&#xff0c;内置CO和FHMM两种分解预测方法&#xff0c;适合在PyCharm中直接导入调试。资源共1046个文件&#xff0c;460.46MB&#xff0c;以Python源…

作者头像 李华
网站建设 2026/9/10 2:34:30

在线视频压缩实战:90%体积缩减的四层技术逻辑

1. 项目概述&#xff1a;为什么“在线视频压缩”成了2024年最被低估的刚需技能&#xff1f;你有没有遇到过这样的场景&#xff1a;拍了一段3分钟的旅行vlog&#xff0c;用手机原生相机录下来——文件大小直接飙到1.2GB&#xff1b;想发到朋友圈&#xff0c;提示“视频过大&…

作者头像 李华