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

如何使用Nest.js和JWT实现客户端用户登录状态跨页面刷新跳转持久化

登录状态持久化实现方案

下面分两种主流实现思路,可根据项目安全要求选择:

方案1:前端手动存储Token到Web Storage(实现简单)

适合对安全性要求中等的场景,实现成本极低:

  • 第一步:修改handleSubmit逻辑,登录成功后把返回的access_token存入localStorage(永久存储,关闭浏览器也保留)或sessionStorage(仅当前标签页生效,关闭即销毁)
    示例修改代码:
    const handleSubmit = async (evt: React.FormEvent) => {
        evt.preventDefault();
        try {
            const res = await fetch('http://localhost:3001/api/auth/login', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(formData),
            });
            const response = await res.json();
            // 新增:存储token到本地
            localStorage.setItem('access_token', response.access_token);
            // TODO replace placeholder with .env var
            const user = jwt.verify(response.access_token, 'placeholder');
            setUser(user);
            history.push('/');
        } catch (err) {
            // Handle error
        }
    };
    
  • 第二步:在全局UserProvider初始化时读取本地存储的Token,恢复登录状态
    你需要找到定义UserContext的Provider组件,新增初始化逻辑:
    const UserProvider = ({ children }) => {
      const [user, setUser] = useState(null);
      // 新增:页面加载时校验本地token恢复登录状态
      useEffect(() => {
        const token = localStorage.getItem('access_token');
        if (token) {
          try {
            const decodedUser = jwt.verify(token, 'placeholder'); // 密钥替换为.env变量
            setUser(decodedUser);
          } catch (err) {
            // token过期/非法,清理无效数据
            localStorage.removeItem('access_token');
            setUser(null);
          }
        }
      }, []);
    
      return (
        <UserContext.Provider value={[user, setUser]}>
          {children}
        </UserContext.Provider>
      )
    }
    
  • 后续接口请求注意:每次发请求需要在请求头携带Token,示例:
    fetch('你的接口地址', {
      headers: {
        'Authorization': `Bearer ${localStorage.getItem('access_token')}`
      }
    })
    
  • 注意事项:Web Storage存在XSS攻击风险,若被注入恶意脚本可直接读取到Token,需做好页面XSS防护(用户输入转义、禁止加载不可信第三方脚本等)。

方案2:HttpOnly Cookie自动存储(安全性更高,推荐大型项目使用)

该方案将Token交给浏览器自动管理,JS无法读取Token,可完全避免XSS窃取Token的风险:

  • 第一步:修改Nest服务端登录接口,返回响应时添加Set-Cookie响应头,将access_token写入Cookie,配置参数:
    • httpOnly: true:禁止JS读取Cookie
    • secure: true:生产环境HTTPS下才发送Cookie
    • sameSite: 'lax':避免CSRF攻击
    • path: '/':全站生效
  • 第二步:放开前端请求中注释的credentials: "include"配置,所有跨域请求都会自动携带服务端下发的Cookie
  • 第三步:在全局UserProvider初始化时,调用后端提供的/api/auth/me接口获取当前登录用户信息,恢复登录状态,示例:
    const UserProvider = ({ children }) => {
      const [user, setUser] = useState(null);
      const [loading, setLoading] = useState(true);
      useEffect(() => {
        const fetchCurrentUser = async () => {
          try {
            const res = await fetch('http://localhost:3001/api/auth/me', {
              credentials: 'include'
            });
            if (res.ok) {
              const userInfo = await res.json();
              setUser(userInfo);
            }
          } catch (err) {
            setUser(null);
          } finally {
            setLoading(false);
          }
        }
        fetchCurrentUser();
      }, []);
      // 可以加loading状态避免未拿到用户信息时页面跳转异常
      if (loading) return <Loading />
      return (
        <UserContext.Provider value={[user, setUser]}>
          {children}
        </UserContext.Provider>
      )
    }
    

通用补充优化

  • 路由跳转不需要额外处理登录状态,只要UserProvider包裹在路由组件外层,路由切换时Context内的用户状态不会丢失
  • 统一处理接口401响应:所有请求返回401状态码时,直接清理本地存储的Token/ Cookie,跳转至登录页,避免过期状态残留
  • 可搭配redux-persist等状态持久化工具使用,如果你项目中用了Redux作为全局状态管理,可直接配置persist规则自动持久化用户状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 23:36:03