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

Next.js中如何持久化存储客户端JWT 重启浏览器/设备不丢失

问题原因

你当前使用的useState是组件内存级状态,仅在当前页面的组件生命周期内生效,页面刷新、浏览器关闭后内存被回收,存储的值自然会被清空,完全不具备持久化能力。另外你原来写的useState(String)本身写法有误,传入的是String构造函数而非具体的初始值,正常初始化应该传入对应类型的初始值,比如空字符串''。

实现方案

要实现浏览器重启、设备重启后仍可读取的持久化存储,直接用浏览器原生的localStorage即可,它是持久化存储,除非用户手动清除浏览器缓存数据,否则写入的数据会永久保留,完全满足你24小时JWT留存的需求。
注意Next.js默认带服务端渲染(SSR/SSG),服务端环境下没有window对象,直接访问localStorage会抛错,需要做客户端环境判断。

具体实现步骤

  • 组件初始化时,优先从localStorage读取之前存储的JWT作为storedVal的初始值
  • 每次更新storedVal时,同步把值写入localStorage
  • 额外增加JWT过期校验逻辑:存储时同时记录JWT的生成时间,读取时先判断是否超出24小时有效期,过期就直接清除旧值,触发重新生成流程,避免使用无效token

改造后的代码示例

import { useState, useEffect } from 'react'
// 项目里其他依赖比如VStack、Heading、Button、connect相关逻辑保持原有导入不变

const JWT_STORAGE_KEY = 'lit_protocol_jwt'
const JWT_MAX_AGE = 24 * 60 * 60 * 1000 // 24小时有效期,单位毫秒

export default function Home(props: any) {
  const [storedVal, setStoredVal] = useState<string>('')
  const [connected, setConnected] = useState(false) // 原有connected状态逻辑保持不变

  // 组件挂载到客户端后,从localStorage读取初始值
  useEffect(() => {
    const storedData = localStorage.getItem(JWT_STORAGE_KEY)
    if (!storedData) return

    try {
      const { value, expireAt } = JSON.parse(storedData)
      // 未过期才赋值,过期直接清除旧数据
      if (Date.now() < expireAt) {
        setStoredVal(value)
      } else {
        localStorage.removeItem(JWT_STORAGE_KEY)
      }
    } catch (e) {
      // 数据格式异常直接清空
      localStorage.removeItem(JWT_STORAGE_KEY)
    }
  }, [])

  function storePersistence(jwtValue: string) {
    setStoredVal(jwtValue)
    // 写入localStorage的同时记录过期时间
    const storageData = {
      value: jwtValue,
      expireAt: Date.now() + JWT_MAX_AGE
    }
    localStorage.setItem(JWT_STORAGE_KEY, JSON.stringify(storageData))
  }

  function printPersistence() {
    console.log('当前存储的JWT:', storedVal)
  }

  // 原有connect逻辑保持不变
  const connect = () => {
    setConnected(true)
    // 登录/注册流程拿到第三方返回的新JWT后,直接调用storePersistence传入JWT即可
    // 示例:storePersistence(接口返回的jwt字符串)
  }

  return (
    <>
      <VStack>
        <Heading as='h3'>Connect to see unity app</Heading>

        {
          !connected ? <Button variant='solid' onClick={connect}>Connect</Button> : <Text>Now you can click on protected path link at the bottom</Text>
        }<br></br>

        <Button variant='solid' onClick={() => storePersistence('I set this')}>Store Persistence</Button>
        <Button variant='solid' onClick={printPersistence}>Check Persistence</Button>

      </VStack>
    </>
  )
}

注意事项

  • 不要用sessionStorage替代,它的生命周期仅在当前标签页生效,标签页关闭后数据就会被清除,不符合你的需求
  • 如果需要存储更大量的数据、或者需要更强的持久化能力,可以替换为IndexedDB存储,但对于单条JWT字符串的场景,localStorage是最轻量、实现成本最低的方案
  • 该方案在Next.js的Pages Router、App Router客户端组件下均可正常运行,不会触发服务端渲染报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:12:19