Laravel + Vue3 前后端分离管理后台的主流方案是 Laravel 作为纯 API 后端、Vue3 用 Vite 构建独立 SPA,认证统一采用 Sanctum;因其轻量(仅 personal_access_tokens 表)、无需 OAuth2 复杂流程、天然适配 SPA 的 CSRF+Token 双机制,且与 Laravel11 集成顺滑,而 Passport 适用于需第三方授权的开放平台场景。

直接上结论:Laravel + Vue3 前后端分离式管理后台,当前主流方案是「Laravel 作为纯 API 后端(不渲染任何 Blade 视图),Vue3 用 Vite 独立构建 SPA,认证统一走 Sanctum(非 Passport)」。选错认证方式或混合使用 Blade + Vue 组件,后续会卡在跨域、token 失效、权限校验绕过等真实问题上。
为什么不用 Passport 而推荐 Sanctum
Passport 是 OAuth2 实现,适合多客户端(App、第三方网站)场景,但管理后台几乎不需要授权码流程、client_secret 管理、scopes 动态分配这些能力。它引入额外数据库表(oauth_clients、oauth_access_tokens)、中间件链更长、调试时 token 解析失败错误信息模糊(比如 TokenMismatchException 或空响应无日志)。
Sanctum 更轻量:只依赖一个 personal_access_tokens 表,token 存 localStorage,通过 auth:sanctum 中间件校验,配合 Laravel 的 session cookie(用于 Web 端 CSRF 保护)即可完成登录态维持。实际项目中,90% 的后台系统用 Sanctum 就够用,且升级 Laravel11 后默认集成更顺滑。
要点:
立即学习“前端免费学习笔记(深入)”;
- 安装后必须运行
php artisan sanctum:install并迁移(php artisan migrate) -
config/auth.php中guards.api.driver应设为sanctum,不是passport - 前端登录成功后,
localStorage.setItem('auth_token', response.data.token)即可,无需处理 refresh token 流程
Vue3 项目如何与 Laravel API 正确通信
常见错误是把 Laravel 当作静态资源服务器,把 Vue 构建产物扔进 public/ 目录,再用 Blade 加载 —— 这会导致热更新失效、路由 404、vue-router history 模式跳转白屏。正确做法是 Vue3 项目完全独立,用 Vite 的代理功能转发请求到 Laravel 开发服务器。
在 Vue3 项目的 vite.config.ts 中配置:
export default defineConfig({
server: {
proxy: {
'/api': {
target: 'http://laravel.test',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '/api')
}
}
}
})
这样 axios.get('/api/user') 实际请求的是 http://laravel.test/api/user,开发时无跨域,上线后由 Nginx 反向代理统一收敛到 Laravel 后端。注意:target 必须是完整 URL(含协议或域名),不能写成 localhost:8000(Vite 代理不识别端口别名)。
其他关键点:
- 不要在
main.js里硬编码baseURL,应从环境变量读取(VUE_APP_API_BASE_URL),开发/测试/生产环境切换才可控 - 所有 API 请求必须携带
Authorization: Bearer <token>,且该 token 必须来自后端登录接口返回,不能前端生成 - 登出时调用
POST /api/logout(Laravel Sanctum 提供),并清空localStorage和axios实例的 header 缓存
权限控制必须落在 Laravel 中间件,而非前端 v-if
看到 v-if="user.role === 'admin'" 或 router.beforeEach 里只检查本地角色字段,基本等于裸奔。用户可以轻松篡改 localStorage 里的 role 字段,绕过前端判断,直接发请求到受保护接口。
Laravel 层必须做两件事:
- 路由分组加
auth:sanctum中间件,保证未登录无法访问 - 具体操作加策略(Policy)或门面(Gate),例如
@can('delete', App\Models\Customer::class),且该判断必须基于当前认证用户的id查询数据库权限,不能依赖传入的 role 字符串
Vue 端只需展示「按钮是否渲染」,逻辑由后端返回的 can_delete: true/false 字段驱动,这个字段本身也应来自 Laravel 的 Gate::allows() 结果,而不是前端拼接判断。
部署时前后端物理分离的最小配置要点
上线不是把 dist/ 放进 Laravel 项目就完事。真正分离意味着:前端静态资源由 Nginx/Apache 直接服务(无 PHP 解析),后端 API 由另一个 location 块反向代理到 Laravel 的 PHP-FPM 或 Swoole 进程。
Nginx 示例片段:
location / {
root /var/www/vue-frontend/dist;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
这里容易忽略的是 CORS 配置 —— Laravel 默认不开启,需在 app/Http/Middleware/TrustProxies.php 中设置可信域名,并安装 fruitcake/laravel-cors 包启用全局跨域(仅开发环境需要,生产环境靠 Nginx 代理规避)。
最后提醒:Laravel 的 APP_URL 和 Vue 的 VUE_APP_API_BASE_URL 在不同环境必须严格对应,尤其当使用子路径部署(如 https://example.com/admin/)时,Vue 的 base 配置和 Laravel 的 url() 辅助函数行为要同步验证,否则会出现资源 404 或 API 请求地址错位。


















