Vue 3中语音验证码登录需后端生成并存Redis,前端用Pinia持久化token,通过路由守卫和axios拦截器统一管理登录态,认证方式不同但状态模型一致。

Vue 3 中实现手机动态语音验证码登录(即用户点击后,系统自动拨打手机号并语音播报6位数字验证码),其登录状态管理不能脱离标准的安全逻辑——语音验证码本身不直接管理状态,而是作为身份核验的一环,最终由后端签发 Token,前端再交由状态管理方案统一维护。
下面从三个关键层面讲清楚如何结合:
✅ 一、语音验证码的接入逻辑(前端 + 后端协作)
语音验证码不是前端能独立完成的功能,它依赖第三方通信平台(如容联云、腾讯云·短信与语音、阿里云语音服务):
-
前端只负责:
立即学习“前端免费学习笔记(深入)”;
- 触发「请求语音验证码」按钮(传手机号)
- 校验手机号格式(
/^1[3-9]\d{9}$/) - 禁用按钮 + 倒计时(防重复触发,建议存
localStorage或pinia/persist持久化倒计时)
-
后端必须做:
- 接收手机号,生成 6 位随机码(
Math.random().toString(36).substr(2, 6).toUpperCase()不安全,应使用crypto.randomUUID()或服务端安全随机) - 调用语音 SDK 拨打该号码,并将验证码通过 TTS 播报(例如:“您的验证码是 3 8 2 9 1 7”)
- 将验证码 + 手机号 + 过期时间(如 5 分钟)存入 Redis(带 TTL),绝不存明文到前端或 localStorage
- 接收手机号,生成 6 位随机码(
⚠️ 注意:语音验证码和短信验证码共用同一套校验逻辑,只是下发通道不同。前端调用的是同一个
/api/voice/send接口,而非自己“合成语音”。
✅ 二、登录态如何管理(Pinia + Token 持久化)
推荐使用 Pinia + pinia-plugin-persistedstate(支持 localStorage / sessionStorage / IndexedDB):
// stores/user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useUserStore = defineStore('user', () => {
const token = ref<string | null>(null)
const userInfo = ref<any>(null)
const loginByVoice = async (phone: string, code: string) => {
const res = await api.loginByVoice({ phone, code }) // 调用 /api/voice/login
token.value = res.data.token
userInfo.value = res.data.user
}
const logout = () => {
token.value = null
userInfo.value = null
}
return { token, userInfo, loginByVoice, logout }
}, {
persist: true // 自动持久化到 localStorage
})- 登录成功后,
token自动写入localStorage - 页面刷新后,Pinia 会从
localStorage恢复状态 - 所有需要鉴权的 API 请求,通过 axios 拦截器自动携带
Authorization: Bearer ${token}
✅ 三、路由守卫与状态同步(防止未登录跳转)
在 router/index.ts 中添加全局前置守卫:
router.beforeEach(async (to, from, next) => {
const userStore = useUserStore()
// 非登录页且无 token → 重定向到登录页
if (to.meta.requiresAuth && !userStore.token) {
next({ name: 'Login' })
return
}
// 有 token 但 userInfo 为空 → 尝试拉取用户信息(可选)
if (userStore.token && !userStore.userInfo) {
try {
await userStore.fetchUserInfo()
} catch {
userStore.logout()
next({ name: 'Login' })
return
}
}
next()
})? 补充:语音验证码登录成功后,后端返回的 JWT 应含
exp(过期时间)、phone(用于识别用户)、role(权限标识),前端无需解析,仅作透传和存储。
❗常见误区提醒
- × 前端生成语音验证码 → 安全性为零,必须由后端生成并下发
- × 把语音验证码存在
localStorage→ 明文泄露风险,只存 token - × 倒计时仅靠
ref<number>→ 刷新丢失,需用localStorage+ 初始化读取 - × 登录后不校验 token 有效性就放行路由 → 必须配合后端
/me或解码 JWT 的exp做兜底
不需要额外封装“语音登录专用状态”,它和短信登录、账号密码登录共享同一套用户状态模型。区别只在认证方式入口不同,状态管理始终围绕 token 和 userInfo 展开。


















