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

使用React+Express+JWT技术栈时 应在哪里调用接口验证用户登录状态

基于React+Express+JWT的登录状态校验实现方案

第一步:后端(Express)接口实现

首先需要实现JWT校验中间件和登录状态校验接口,核心逻辑在校验JWT的签名有效性、是否过期,同时支持识别已吊销的JWT:

// 提前安装依赖:npm install jsonwebtoken cookie-parser
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const express = require('express');
const app = express();
app.use(cookieParser());

// JWT密钥,必须和签发登录token时使用的密钥完全一致
const JWT_SECRET = process.env.JWT_SECRET || 'your_custom_secret_key';

// 通用JWT校验中间件
const authMiddleware = (req, res, next) => {
  const token = req.cookies.jwt;
  if (!token) {
    return res.status(401).json({ isLoggedIn: false, message: '未携带登录凭证' });
  }
  try {
    // 校验JWT的签名和有效期
    const decoded = jwt.verify(token, JWT_SECRET);
    req.user = decoded; // 解析出的用户信息挂载到请求对象上
    next();
  } catch (err) {
    return res.status(401).json({ isLoggedIn: false, message: '登录状态已失效' });
  }
};

// 登录状态校验专用接口
app.get('/api/auth/check', authMiddleware, (req, res) => {
  res.json({
    isLoggedIn: true,
    userInfo: {
      id: req.user.id,
      username: req.user.username
      // 按需返回其他用户字段
    }
  });
});

注意:签发JWT时建议把jwt存入HttpOnly类型的Cookie,防止XSS攻击窃取凭证,示例配置如下:

res.cookie('jwt', token, {
  httpOnly: true,
  secure: process.env.NODE_ENV === 'production', // 生产环境HTTPS下开启
  maxAge: 7 * 24 * 60 * 60 * 1000 // 有效期和JWT本身的有效期保持一致
});

第二步:前端(React)路由改造

原来的同步判断Cookie逻辑需要改成异步校验,增加加载状态避免页面闪跳:

import { Route, Redirect } from "react-router-dom";
import { useState, useEffect } from "react";
import axios from "axios";

export const PrivateRoute = ({ children, ...rest }) => {
  // 校验中状态、登录状态
  const [loading, setLoading] = useState(true);
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    const checkAuthStatus = async () => {
      try {
        // withCredentials必须开启,才能携带Cookie请求后端接口
        const res = await axios.get('/api/auth/check', { withCredentials: true });
        setIsLoggedIn(res.data.isLoggedIn);
        // 此处可将返回的用户信息存入全局状态(Context/Redux/Zustand等)供其他组件使用
      } catch (err) {
        setIsLoggedIn(false);
      } finally {
        setLoading(false);
      }
    };
    checkAuthStatus();
  }, []);

  // 校验过程中显示加载态,避免登录/目标页闪跳
  if (loading) return <div>加载中...</div>;

  return (
    <Route
      {...rest}
      render={({ location }) =>
        isLoggedIn ? (
          children
        ) : (
          <Redirect to={{ pathname: "/login", state: { from: location } }} />
        )
      }
    />
  );
};

如果使用React Router v6,只需要把返回的Route组件替换为Outlet即可,校验逻辑完全一致。

可优化的细节

  • 增加全局状态缓存:把校验后的登录状态和用户信息存入全局状态中,路由切换时直接读缓存,只有页面刷新时才重新调用校验接口,减少不必要的请求
  • 全局响应拦截:给axios加响应拦截器,只要任意业务接口返回401状态码,直接清除本地登录状态跳转到登录页,避免状态不同步
  • 避免loading闪屏:可以给加载状态加100ms以内的防抖,请求很快返回的话不显示loading组件,体验更好

核心逻辑说明

不推荐前端直接校验JWT的原因是:前端只能校验JWT的格式和有效期,无法识别已被后端吊销的凭证(比如用户主动登出、账号被封禁的场景),后端统一校验安全性更高。
接口调用的最佳位置是PrivateRoute路由守卫中统一处理,所有需要登录的路由都会自动走校验逻辑,不需要每个业务页面单独实现。

内容的提问来源于stack exchange,提问作者Augustin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 17:57:00