Next.js 15中实现Refresh Token Rotation的问题咨询及方案验证
Next.js 15中实现Refresh Token Rotation的问题咨询及方案验证
大家好,我正在基于Next.js 15开发应用,授权部分打算采用JWT+Refresh Token的方案,具体流程如下:
- 当用户访问受限页面时,系统先检查是否存在
access_tokenCookie(有效期7分钟的JWT,包含userId):- 如果有效:重新生成该JWT并续期7分钟,更新Cookie,获取用户会话后继续访问
- 如果无效:检查是否存在
refresh_tokenCookie(有效期7天的普通令牌):- 若不存在:重定向到登录页
- 若存在:在KV/Redis数据库中验证该令牌是否有效,获取对应的
userId,重新生成access_token和refresh_token,更新Cookie,获取用户会话后继续访问
我遇到的问题
卡在Refresh Token Rotation这一步上:
比如访问app/dashboard/page.js这类页面时,我能读取Cookie做验证,但没法直接更新Cookie——因为Next.js里Cookie只能通过Server Actions或者路由处理器来写入。
我试过几种方法都没解决:
- 写了个叫
UpdateAccessCookies的服务端组件放在页面里,专门用来更新Cookie,但这样会导致系统进入循环 - 尝试用API接口,但POST请求时没法正确获取Cookie,而且我更倾向于用Server Actions来实现
给大家看部分示例代码
注册页面(app/register/page.js)
import { getCurrentSession } from '@/services/session'; import { RegisterForm } from './Form'; export default async function Register() { const { session, data } = await getCurrentSession(); return ( <> <h1>Register</h1> <RegisterForm/> </> ); }
会话处理服务(services/session.js)
'use server' // ... 相关导入 ... export async function getCurrentSession() { const accessToken = await getCookie('access_token'); let data = {}; if (accessToken) { const jwtValidation = await validarJWT(accessToken); if (jwtValidation) { data.userId = jwtValidation.userId; data.jwt = { token: await createJWT({ userId: jwtValidation.userId }), expiraEm: JWT_EXPIRES_IN, }; } } if (!data.userId) { const refreshToken = await getCookie('refresh_token'); if (!refreshToken) { return { session: null, data: null }; } data.userId = await getStorageAdapterData('refresh_token', refreshToken); if (!data.userId) { return { session: null, data: null }; } data.jwt = { token: await createJWT({ userId: data.userId }), expiraEm: JWT_EXPIRES_IN, }; data.refreshToken = { token: await createRefreshToken(data.userId, refreshToken), expiraEm: SESSION_EXPIRES_IN, }; } const session = await getStorageAdapterData('session', data.userId); if (!session) { return { session: null, data: null }; } return { session, data }; }
我之前尝试过几个更新Cookie的位置:
- 页面里调用
getCurrentSession之后直接更新(最理想的位置,但做不到) - 在
session.js里生成新令牌后直接更新 - 单独做一个
RefreshCookies组件放在页面里(代码如下)
旧版RefreshCookies组件(导致循环)
// Register Page 2 import { getCurrentSession } from '@/services/session'; import { RegisterForm } from './Form'; import RefreshCookies from '@/components/refresh-cookies'; export default async function Register() { const { session, data } = await getCurrentSession(); return ( <> <h1>Register</h1> <RegisterForm/> <RefreshCookies jwt={data?.jwt} refreshToken={data?.refreshToken} /> </> ); }
// Refresh-cookies.js 'use client'; import { useEffect, useState } from 'react'; import { createCookie } from '@/services/cookies'; async function updateCookies(jwt, refreshToken) { if (jwt) { await createCookie('access_token', jwt.token, jwt.expires); } if (refreshToken) { await createCookie( 'refresh_token', refreshToken.token, refreshToken.expires ); } } export default function RefreshCookies({ jwt, refreshToken }) { const [Updatedcookies, setUpdatedCookies] = useState(false); useEffect(() => { async function update() { if (!Updatedcookies && (jwt || refreshToken)) { await updateCookies(jwt, refreshToken); } } update(); }, [jwt, refreshToken, Updatedcookies]); }
我调整后的方案(目前能运行)
我修改了RefreshCookies组件里的判断逻辑,现在代码如下:
// Refresh-cookies.js 'use client'; import { useEffect, useState } from 'react'; import { createCookie } from '@/services/cookies'; async function updateCookies(jwt, refreshToken) { if (jwt) { await createCookie('access_token', jwt.token, jwt.expires); } if (refreshToken) { await createCookie( 'refresh_token', refreshToken.token, refreshToken.expires ); } } export default function RefreshCookies({ jwt, refreshToken }) { const [Updatedcookies, setUpdatedCookies] = useState(false); useEffect(() => { async function update() { if (refreshToken || (!Updatedcookies && jwt)) { // 这里做了修改 await updateCookies(jwt, refreshToken); } } update(); }, [jwt, refreshToken, Updatedcookies]); }
现在更新Cookie的逻辑变成:
- 如果收到了
refreshToken(说明access_token已过期或失效),就更新Cookie - 或者如果收到了
jwt且还没更新过Cookie,就更新Cookie
这样就不会进入循环了,目前功能正常。想问问大家这个方案有没有什么潜在问题?或者有没有更优的实现方式?
另外补充:我不想用第三方库,也不想用中间件做验证——因为中间件会在每个受限页面请求都做检查,会显著增加请求耗时。
备注:内容来源于stack exchange,提问作者user2611485
相关产品推荐
相关产品推荐

