Nuxt 3 结合 Laravel 9 与 Sanctum 认证方案实现咨询
Nuxt3 + Laravel Sanctum 身份认证实现方案
一、基础环境配置
Laravel Sanctum 端配置
- 在
.env中设置允许的前端域名:SANCTUM_STATEFUL_DOMAINS=your-nuxt-app-domain.test SESSION_DOMAIN=.your-root-domain.test # 跨域场景下设置根域名 - 配置
config/cors.php,允许前端域名的请求:'allowed_origins' => [env('FRONTEND_URL', 'http://your-nuxt-app-domain.test')], 'allowed_methods' => ['*'], 'allowed_headers' => ['*'], 'supports_credentials' => true,
Nuxt3 端配置
在 nuxt.config.ts 中配置 API 地址与 cookie 规则:
export default defineNuxtConfig({ runtimeConfig: { public: { apiBase: process.env.NUXT_PUBLIC_API_BASE_URL || 'http://your-laravel-api.test' } }, modules: ['@pinia/nuxt'], // 后续用Pinia管理认证状态 cookies: { defaults: { path: '/', sameSite: 'lax' } } })
封装带 Sanctum 要求的请求工具:
// composables/useApi.ts export const useApi = () => { const config = useRuntimeConfig() return $fetch.create({ baseURL: config.public.apiBase, credentials: 'include', // 强制携带cookie,Sanctum依赖此维持会话 headers: { 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' // Sanctum要求的标识头 } }) }
二、登录功能实现
1. 安装并配置 Pinia
执行安装命令:
npm install @pinia/nuxt
创建认证状态管理 store:
// stores/auth.ts import { defineStore } from 'pinia' export const useAuthStore = defineStore('auth', () => { const user = useState('auth_user', () => null) const isAuthenticated = computed(() => !!user.value) // 登录方法 const login = async (credentials: { email: string, password: string }) => { const api = useApi() try { await api('/sanctum/csrf-cookie') // 跨域场景下必须先获取CSRF令牌 const res = await api('/api/login', { method: 'POST', body: credentials }) user.value = res.user return true } catch (err) { console.error('登录失败', err) return false } } // 登出方法 const logout = async () => { const api = useApi() try { await api('/api/logout', { method: 'POST' }) user.value = null } catch (err) { console.error('登出失败', err) } } // 刷新页面后验证登录状态 const fetchUser = async () => { const api = useApi() try { const res = await api('/api/user') user.value = res } catch (err) { user.value = null } } return { user, isAuthenticated, login, logout, fetchUser } })
2. 登录页面实现
<!-- pages/login.vue --> <template> <form @submit.prevent="handleLogin"> <input v-model="form.email" type="email" placeholder="邮箱" required /> <input v-model="form.password" type="password" placeholder="密码" required /> <button type="submit">登录</button> <p v-if="loginError" class="text-red-500">登录失败,请检查账号密码</p> </form> </template> <script setup> const authStore = useAuthStore() const form = reactive({ email: '', password: '' }) const loginError = ref(false) const handleLogin = async () => { loginError.value = false const success = await authStore.login(form) if (success) { navigateTo('/') // 登录成功跳转首页 } else { loginError.value = true } } </script>
三、路由保护:Auth 中间件
全局中间件(拦截所有路由)
创建 middleware/auth.global.ts:
export default defineNuxtRouteMiddleware(async (to) => { const authStore = useAuthStore() await authStore.fetchUser() // 每次路由跳转验证登录状态 // 定义无需认证的路由列表 const publicRoutes = ['/login', '/', '/about'] const isPublicRoute = publicRoutes.includes(to.path) if (!authStore.isAuthenticated && !isPublicRoute) { return navigateTo('/login') // 未登录访问私有路由,跳转登录页 } if (authStore.isAuthenticated && to.path === '/login') { return navigateTo('/') // 已登录访问登录页,跳转首页 } })
局部中间件(仅拦截指定路由)
创建 middleware/auth.ts:
export default defineNuxtRouteMiddleware(async () => { const authStore = useAuthStore() await authStore.fetchUser() if (!authStore.isAuthenticated) { return navigateTo('/login') } })
在需要保护的页面中启用:
<!-- pages/dashboard.vue --> <script setup> definePageMeta({ middleware: 'auth' }) </script>
四、@nuxtjs-alt/auth 包 $auth undefined 问题修复
如果坚持使用该包,需注意以下几点:
- 确保模块正确注册:
// nuxt.config.ts modules: ['@nuxtjs-alt/auth', '@nuxtjs-alt/axios'] - 配置 Sanctum 策略:
auth: { strategies: { sanctum: { provider: 'laravel/sanctum', url: process.env.NUXT_PUBLIC_API_BASE_URL, endpoints: { login: { url: '/api/login', method: 'post' }, logout: { url: '/api/logout', method: 'post' }, user: { url: '/api/user', method: 'get' } } } }, globalMiddleware: true } - 在组件中使用
useAuth()替代nuxtApp().$auth:const { login, user, loggedIn } = useAuth()
内容的提问来源于stack exchange,提问作者Giampy71
相关产品推荐
相关产品推荐

