如何让Axios自动传递Cookie与授权令牌?Laravel Sanctum+Vue.js问题
解决Laravel Sanctum + Vue Axios页面刷新后需重新登录的问题
核心问题分析
你当前在登录时动态添加Axios请求拦截器携带Bearer令牌,但页面刷新后拦截器配置会丢失,且未持久化存储令牌;另外如果是SPA场景,Sanctum推荐使用Cookie会话认证,无需手动处理Bearer令牌。以下分两种场景给出解决方案:
方案一:使用Sanctum SPA Cookie认证(推荐)
这种方式依赖Cookie自动传递会话信息,无需手动管理令牌,更符合SPA场景的最佳实践。
1. 服务端补充配置
打开config/sanctum.php,确保stateful数组包含你的前端域名(比如前端运行在localhost:8080):
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( '%s%s', 'localhost,localhost:8080,127.0.0.1,127.0.0.1:8000,::1', env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '' ))),
或者直接在.env文件中设置:
SANCTUM_STATEFUL_DOMAINS=localhost:8080,127.0.0.1:8080
同时确保登录路由使用web中间件(因为Sanctum会话依赖web会话机制),比如在routes/api.php中:
use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; Route::post('/authenticate', function(Request $request) { $credentials = $request->only('email', 'password'); if (!Auth::attempt($credentials)) { return response()->json(['message' => 'Invalid credentials'], 401); } return response()->json(['user' => Auth::user()]); })->middleware('web');
2. 前端代码调整
修改Vuex Store的signIn action
移除手动设置Axios拦截器的代码,登录后直接通过Cookie会话获取用户信息:
async signIn({commit}, payload) { try{ await axios.get('/sanctum/csrf-cookie'); await axios.post('/api/authenticate', payload); // 登录成功后直接拉取用户信息,Cookie会自动携带 return store.dispatch('getUser'); } catch(e) { throw 'User can not be authenticated'; } }
确保Axios全局配置正确
你的app.js中已经设置了axios.defaults.withCredentials = true,这个配置必须保留,它会让Axios自动携带Cookie。
方案二:使用API Bearer令牌(适合非SPA场景)
如果需要使用Bearer令牌,需将令牌持久化存储,页面刷新后自动读取并配置Axios。
1. 前端代码调整
在app.js初始化时读取本地存储的令牌
import './bootstrap'; import { createApp } from 'vue'; import router from './routes'; import axios from 'axios'; import store from './store/index.js' axios.defaults.withCredentials = true; axios.defaults.baseURL = 'http://127.0.0.1:8000/'; // 页面刷新时读取本地存储的令牌,自动配置Authorization头 const authToken = localStorage.getItem('auth_token'); if (authToken) { axios.defaults.headers.common['Authorization'] = `Bearer ${authToken}`; } import App from './components/App.vue'; store.dispatch('getUser').then(() => { const app = createApp(App); app.use(router); app.use(store); app.mount('#app'); });
修改Vuex Store的signIn action
登录成功后将令牌存入本地存储,并配置Axios默认头:
async signIn({commit}, payload) { try{ await axios.get('/sanctum/csrf-cookie'); const res = await axios.post('/api/authenticate', payload); if(res.data.status_code == 200) { // 将令牌存入本地存储 localStorage.setItem('auth_token', res.data.access_token); // 配置Axios全局Authorization头 axios.defaults.headers.common['Authorization'] = `Bearer ${res.data.access_token}`; return store.dispatch('getUser'); } else { throw res.message; } } catch(e) { throw 'User can not be authenticated'; } }
修改Vuex Store的logout action
登出时清除本地存储的令牌和Axios配置:
async logout({commit}) { await axios.post('/api/logout').then(res => { commit('setUser', null); commit('setAuthenticated', false); // 清除本地存储的令牌 localStorage.removeItem('auth_token'); // 移除Axios的Authorization头 delete axios.defaults.headers.common['Authorization']; }).catch(() => { commit('setUser', null); commit('setAuthenticated', false); localStorage.removeItem('auth_token'); delete axios.defaults.headers.common['Authorization']; }) }
通用注意事项
- 确保
config/cors.php中的allowed_origins包含你的前端域名,supports_credentials设为true - 如果前后端域名不同,需确保浏览器允许第三方Cookie(localhost环境下通常默认允许)
内容的提问来源于stack exchange,提问作者googerdi
相关产品推荐
相关产品推荐

