You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检查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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:01:14