如何检查JWT令牌有效性?Lumen+VueJS鉴权场景问题
解决JWT令牌有效性验证的问题
这个场景我太熟悉了——只靠localStorage.getItem('token')判断登录状态确实很脆弱,毕竟用户手动篡改、令牌过期或者签名失效都没法被检测到。下面给你几个循序渐进的解决方案,从简单到完善:
1. 前端本地初步验证(仅做过期检查)
JWT的payload里包含了过期时间exp字段,你可以在前端解码令牌,对比当前时间判断是否过期。不过要注意:这种方式只能验证过期,无法验证令牌签名是否被篡改,因为前端没有后端的密钥,所以只能做初步校验。
写个简单的工具函数就行:
// 解码JWT令牌(注意:仅解码,不验证签名) function decodeJwt(token) { try { const payload = token.split('.')[1]; return JSON.parse(atob(payload)); } catch (e) { return null; } } // 验证令牌是否过期 function isTokenExpired(token) { const decoded = decodeJwt(token); if (!decoded || !decoded.exp) return true; // 对比当前时间(秒级,JWT的exp是时间戳秒数) return Date.now() / 1000 > decoded.exp; }
然后在Vuex的state初始化或者路由守卫里用:
const state = { isLogged: !!localStorage.getItem('token') && !isTokenExpired(localStorage.getItem('token')) };
2. 后端提供令牌验证接口(最可靠的方式)
前端本地验证有局限性,最靠谱的是让后端来验证令牌的合法性(包括签名、过期、是否在黑名单等)。在Lumen里利用tymon/jwt-auth快速实现一个验证接口:
后端代码(Lumen控制器)
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class AuthController extends Controller { public function validateToken(Request $request) { // 尝试验证令牌 try { // 这里会自动验证令牌的有效性 $user = auth()->authenticate(); return response()->json([ 'valid' => true, 'user' => $user ]); } catch (\Tymon\JWTAuth\Exceptions\TokenExpiredException $e) { return response()->json(['valid' => false, 'message' => '令牌已过期'], 401); } catch (\Tymon\JWTAuth\Exceptions\TokenInvalidException $e) { return response()->json(['valid' => false, 'message' => '令牌无效'], 401); } catch (\Exception $e) { return response()->json(['valid' => false, 'message' => '令牌不存在'], 401); } } }
记得在路由里注册这个接口:
$router->get('/api/auth/validate-token', 'AuthController@validateToken');
前端处理(Vuex + 路由守卫)
在Vuex里加一个action来调用这个接口:
const actions = { async validateToken({ commit }) { const token = localStorage.getItem('token'); if (!token) { commit('SET_LOGGED', false); return; } try { const response = await axios.get('/api/auth/validate-token', { headers: { Authorization: `Bearer ${token}` } }); if (response.data.valid) { commit('SET_LOGGED', true); // 还可以把用户信息存到state里 commit('SET_USER', response.data.user); } else { commit('SET_LOGGED', false); localStorage.removeItem('token'); } } catch (error) { commit('SET_LOGGED', false); localStorage.removeItem('token'); } } }; const mutations = { SET_LOGGED(state, value) { state.isLogged = value; }, SET_USER(state, user) { state.user = user; } };
然后在路由的全局守卫里调用这个action,确保进入页面时验证令牌:
router.beforeEach(async (to, from, next) => { if (to.matched.some(record => record.meta.requiresAuth)) { await store.dispatch('validateToken'); if (!store.state.isLogged) { next({ name: 'Login' }); } else { next(); } } else { next(); } });
3. 全局请求拦截器自动处理令牌失效
即使在初始化时验证了令牌,也可能出现令牌在使用过程中过期的情况,这时候可以用axios的响应拦截器来统一处理401错误:
axios.interceptors.response.use( response => response, error => { if (error.response.status === 401) { // 清除令牌,更新登录状态 localStorage.removeItem('token'); store.commit('SET_LOGGED', false); // 重定向到登录页 router.push({ name: 'Login' }); } return Promise.reject(error); } );
这样不管用户是篡改令牌还是令牌过期,只要发起请求就会被后端返回401,前端自动处理状态。
总结
最优的方案是后端验证接口 + 路由守卫初始化验证 + 请求拦截器兜底:
- 初始化页面时,通过后端接口验证令牌合法性,确保登录状态正确
- 每次请求时,拦截器自动处理401错误,实时更新状态
- 前端本地过期检查可以作为补充,减少不必要的后端请求
内容的提问来源于stack exchange,提问作者Baptiste
相关产品推荐
相关产品推荐

