基于Laravel Passport的SPA如何在API调用时刷新laravel_token
解决Laravel Passport SPA自动刷新laravel_token的方案
嘿,这个问题我在开发Laravel+Vue SPA的时候也碰到过,刚好有一套实用的解决方案,咱们一步步来实现:
1. 后端配置调整
首先确保Passport的令牌过期时间和session配置合理,并且添加一个刷新令牌的接口:
1.1 设置令牌过期时间
在app/Providers/AuthServiceProvider.php的boot方法里,配置access token的过期时间,同时保证session有效期比token长:
public function boot() { $this->registerPolicies(); Passport::routes(); // 设置access token有效期为1小时,session建议配置为2小时以上 Passport::tokensExpireIn(now()->addHour()); }
1.2 创建刷新令牌接口
在routes/api.php中添加一个使用web中间件的接口,利用用户的有效session生成新的laravel_token:
use Illuminate\Http\Request; Route::get('/refresh-token', function (Request $request) { // 检查用户session是否有效 if (!$request->user()) { return response()->json(['error' => 'Session expired'], 401); } // 生成新的API令牌并设置到cookie $newToken = $request->user()->createToken('SPA Access Token')->accessToken; return response()->json(['success' => true]) ->cookie( 'laravel_token', $newToken, config('session.lifetime') * 60, // 和session有效期保持一致 config('session.path'), config('session.domain'), config('session.secure'), true // 开启HttpOnly,提升安全性 ); })->middleware('web');
2. 前端Axios拦截器实现
通过Vue的Axios拦截器,自动处理token过期的情况:
2.1 基础响应拦截器(捕获401后刷新)
在Vue入口文件(比如resources/js/app.js或main.js)中配置Axios:
import axios from 'axios'; import Vue from 'vue'; // 创建Axios实例,确保携带cookie const api = axios.create({ baseURL: '/api', withCredentials: true }); // 响应拦截器:处理401错误并刷新token api.interceptors.response.use( response => response, async (error) => { const originalRequest = error.config; // 仅处理首次401错误,避免无限循环 if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { // 调用刷新token接口 await api.get('/refresh-token'); // 重试原请求 return api(originalRequest); } catch (refreshError) { // 刷新失败,跳转登录页 window.location.href = '/login'; return Promise.reject(refreshError); } } return Promise.reject(error); } ); // 挂载到Vue原型,全局可用 Vue.prototype.$api = api;
2.2 可选:请求前提前刷新token
如果想避免出现401错误,可以在请求前检查token的过期时间,提前刷新:
import jwtDecode from 'jwt-decode'; // 请求拦截器:提前检查token有效期 api.interceptors.request.use(async (config) => { // 从cookie中获取laravel_token const getCookie = (name) => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); return parts.length === 2 ? parts.pop().split(';').shift() : null; }; const token = getCookie('laravel_token'); if (token) { const decoded = jwtDecode(token); const now = Date.now() / 1000; // 如果token在5分钟内过期,提前刷新 if (decoded.exp - now < 300) { try { await api.get('/refresh-token'); } catch (e) { window.location.href = '/login'; } } } return config; });
3. 关键注意事项
- 确保
config/session.php中的lifetime配置比token过期时间长,这样token过期时session仍有效,才能刷新token。 - 必须开启Axios的
withCredentials: true,否则请求不会携带cookie。 - 生产环境建议开启
session.secure,确保cookie仅通过HTTPS传输。
这样配置后,用户在长时间不刷新页面的情况下,token过期时会自动刷新,无需手动操作,大幅提升SPA的用户体验。
内容的提问来源于stack exchange,提问作者Matthias
相关产品推荐
相关产品推荐

