Nuxt 3:如何仅在服务器端存储access_token?
Nuxt3服务器端可修改存储access_token的可行方案
1. 模块级内存缓存(单实例部署)
- 适合单服务器实例场景,利用Node.js模块级变量的持久特性存储token及过期时间,无需额外依赖。
- 核心逻辑:在服务器端工具模块中维护token状态,每次请求前检查有效性,过期则重新从Auth0获取。
示例代码:server/utils/auth0.ts
let cachedToken: string | null = null; let tokenExpiresAt: number = 0; export async function getAuth0Token() { // 提前10秒刷新,避免token在请求过程中过期 if (cachedToken && Date.now() < tokenExpiresAt - 10000) { return cachedToken; } // 调用Auth0客户端凭证流获取token const response = await fetch('https://your-auth0-domain/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: useRuntimeConfig().private.auth0ClientId, client_secret: useRuntimeConfig().private.auth0ClientSecret, grant_type: 'client_credentials', audience: 'your-api-audience' }) }); const data = await response.json(); cachedToken = data.access_token; tokenExpiresAt = Date.now() + (data.expires_in * 1000); return cachedToken; }
在服务器API中调用:server/api/fetch-data.ts
import { getAuth0Token } from '~/server/utils/auth0'; export default defineEventHandler(async (event) => { const token = await getAuth0Token(); // 携带token请求后端REST服务 const data = await fetch('https://your-backend-api/data', { headers: { Authorization: `Bearer ${token}` } }); return data.json(); });
2. 服务器插件挂载缓存(符合Nuxt架构的单实例方案)
- 将缓存逻辑封装为Nuxt服务器插件,挂载到Nitro应用实例上,更贴合Nuxt的扩展规范。
示例代码:server/plugins/auth0-cache.ts
export default defineNitroPlugin((nitroApp) => { nitroApp.auth0Cache = { token: null as string | null, expiresAt: 0 }; }); // 扩展TypeScript类型提示(可选) declare module 'nitropack' { interface NitroApp { auth0Cache: { token: string | null; expiresAt: number; }; } }
修改工具函数使用插件缓存:server/utils/auth0.ts
export async function getAuth0Token(nitroApp: NitroApp) { const { token, expiresAt } = nitroApp.auth0Cache; if (token && Date.now() < expiresAt - 10000) { return token; } const response = await fetch('https://your-auth0-domain/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: useRuntimeConfig().private.auth0ClientId, client_secret: useRuntimeConfig().private.auth0ClientSecret, grant_type: 'client_credentials', audience: 'your-api-audience' }) }); const data = await response.json(); nitroApp.auth0Cache.token = data.access_token; nitroApp.auth0Cache.expiresAt = Date.now() + (data.expires_in * 1000); return data.access_token; }
API中调用方式:server/api/fetch-data.ts
import { getAuth0Token } from '~/server/utils/auth0'; export default defineEventHandler(async (event) => { const token = await getAuth0Token(event.context.nitroApp); const data = await fetch('https://your-backend-api/data', { headers: { Authorization: `Bearer ${token}` } }); return data.json(); });
3. 外部缓存存储(多实例/集群部署)
- 多实例或集群场景下,内存缓存无法跨实例共享,需使用Redis、Memcached等外部缓存服务,确保所有实例共用同一有效token。
- 示例以Redis为例,先安装依赖:
npm install ioredis
示例代码:server/utils/redis.ts
import Redis from 'ioredis'; const redis = new Redis({ host: useRuntimeConfig().private.redisHost, port: Number(useRuntimeConfig().private.redisPort), password: useRuntimeConfig().private.redisPassword // 按需配置 }); export default redis;
server/utils/auth0.ts
import redis from './redis'; export async function getAuth0Token() { // 从Redis读取缓存的token和过期时间 const [cachedToken, expiresAtStr] = await redis.mget('auth0_token', 'auth0_token_expires_at'); const expiresAt = Number(expiresAtStr); if (cachedToken && Date.now() < expiresAt - 10000) { return cachedToken; } // 从Auth0获取新token const response = await fetch('https://your-auth0-domain/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: useRuntimeConfig().private.auth0ClientId, client_secret: useRuntimeConfig().private.auth0ClientSecret, grant_type: 'client_credentials', audience: 'your-api-audience' }) }); const data = await response.json(); const newExpiresAt = Date.now() + (data.expires_in * 1000); // 将token存入Redis,设置与token一致的过期时间 await redis.multi() .set('auth0_token', data.access_token) .set('auth0_token_expires_at', newExpiresAt.toString()) .expire('auth0_token', data.expires_in) .expire('auth0_token_expires_at', data.expires_in) .exec(); return data.access_token; }
API中的使用方式与单实例方案一致。
内容的提问来源于stack exchange,提问作者David H
相关产品推荐
相关产品推荐

