SSR模式Nuxt应用中Directus认证配置及Cookie问题排查
问题根源分析
- 跨域限制:Nuxt(app.netlify.app/localhost)与Directus(admin.myserver.com)分属不同域名,跨域场景下Cookie的设置、携带受浏览器同源策略严格限制,当前Directus Cookie配置未适配跨域需求。
- SSR特性:SSR时服务器端发起的请求无法直接读取客户端Cookie,页面刷新后服务器端无认证信息导致会话丢失;同时开发环境localhost为HTTP协议,
Secure=true的Cookie无法被浏览器存储(Firefox对此校验更严格)。
你的问题逐个解答
是否是SSR导致的问题?
是。SSR的服务器端/客户端请求上下文分离,跨域场景下服务器端无法获取客户端Cookie,刷新后服务器端发起的认证请求无Cookie凭证,直接导致会话失效。配置是否正确?
不正确:- Directus的Cookie域名设为
admin.myserver.com,仅该域名下的请求会携带Cookie,Nuxt域名不在范围内,跨域请求无法持久化Cookie。 - 开发环境localhost为HTTP,
SESSION_COOKIE_SECURE=true会导致Cookie无法被浏览器存储。 SameSite=None必须搭配Secure=true,但开发环境不满足HTTPS条件,二者冲突。
- Directus的Cookie域名设为
是否应该使用'json'模式手动处理Cookie?
可以作为替代方案,但需要手动管理token的存储、携带和刷新,复杂度较高,仅适合无法使用代理的场景。是否需要在Nuxt中使用代理模块?
是,这是最优解决方案。通过代理让Nuxt请求转发至Directus,实现同源请求,彻底规避跨域Cookie限制。是否应该在Nuxt的/server目录下创建API?
本质是自定义代理层,和使用代理模块效果一致,但需要手动编写转发逻辑,不如代理模块便捷高效。
最优解决方案:Nuxt代理+Directus配置调整
步骤1:安装并配置Nuxt代理模块
- 安装代理依赖:
npm install @nuxtjs/proxy
- 在
nuxt.config.ts中配置代理:
export default defineNuxtConfig({ modules: ['@nuxtjs/proxy'], proxy: { '/directus': { target: 'https://admin.myserver.com', changeOrigin: true, pathRewrite: { '^/directus': '' } } }, devtools: { enabled: true } })
步骤2:修改Directus SDK配置
将Directus请求地址改为代理路径,实现同源请求:
const directus = createDirectus('/directus') .with(rest({ credentials: 'include' })) .with(authentication('session', { credentials: 'include' })); async function userLogin() { try { return await directus.login('username', 'password'); } catch (error) { console.error(error); } }
步骤3:调整Directus Cookie配置
开发环境(localhost):
REFRESH_TOKEN_COOKIE_DOMAIN=localhost REFRESH_TOKEN_COOKIE_SECURE=false REFRESH_TOKEN_COOKIE_SAME_SITE=lax SESSION_COOKIE_DOMAIN=localhost SESSION_COOKIE_SECURE=false SESSION_COOKIE_SAME_SITE=lax
- 关闭
Secure适配HTTP环境;SameSite设为lax避免跨域限制。
生产环境:
REFRESH_TOKEN_COOKIE_SECURE=true REFRESH_TOKEN_COOKIE_SAME_SITE=none SESSION_COOKIE_SECURE=true SESSION_COOKIE_SAME_SITE=none
- 无需设置
DOMAIN,代理后请求来自Nuxt域名(app.netlify.app),Directus会自动将Cookie域名设为请求来源域名,实现同源Cookie持久化。
替代方案:手动处理Token(JSON认证模式)
若无法使用代理,可采用JSON模式手动管理token:
- 初始化Directus SDK:
const directus = createDirectus('https://admin.myserver.com') .with(rest()) .with(authentication('json'));
- 登录并存储token到Nuxt Cookie:
async function userLogin() { try { const { access_token, refresh_token } = await directus.login('username', 'password'); // 用Nuxt的useCookie存储,确保服务器端/客户端都能访问 const accessTokenCookie = useCookie('directus_access_token', { secure: process.env.NODE_ENV === 'production', sameSite: 'none', domain: process.env.NODE_ENV === 'production' ? 'app.netlify.app' : undefined }); const refreshTokenCookie = useCookie('directus_refresh_token', { secure: process.env.NODE_ENV === 'production', sameSite: 'none', domain: process.env.NODE_ENV === 'production' ? 'app.netlify.app' : undefined }); accessTokenCookie.value = access_token; refreshTokenCookie.value = refresh_token; return { access_token, refresh_token }; } catch (error) { console.error(error); } }
- 请求时携带token:
function getAuthenticatedDirectus() { const accessToken = useCookie('directus_access_token'); return createDirectus('https://admin.myserver.com') .with(rest()) .with(authentication('json', { token: accessToken.value })); } // 示例:获取当前用户信息 async function getCurrentUser() { const directus = getAuthenticatedDirectus(); return directus.request(readMe()); }
- 补充token刷新逻辑:在Nuxt插件中监听token过期,用refresh_token重新获取access_token。
内容的提问来源于stack exchange,提问作者Posoroko
相关产品推荐
相关产品推荐

