AWS Cognito与Amplify跨应用会话获取:配置Amplify通过next-auth.session-token Cookie调用Auth.currentSession()
解决Amplify Auth无法读取NextAuth生成的Cognito会话问题
核心问题很明确:Amplify Auth默认只会识别自己创建的Cognito会话Cookie,而你的认证流程是通过NextAuth完成的,生成的Cookie是next-auth.session-token,Amplify并不知道如何从这个Cookie里提取有效会话信息。下面是一步步的解决思路和代码实现:
1. 先确保NextAuth的Cookie支持跨端口访问
首先得让4200端口的应用能读取到3000端口生成的next-auth.session-token,需要调整NextJS应用里的NextAuth配置:
// NextJS应用中的[...nextauth].js文件 export default NextAuth({ providers: [ // 这里保留你已有的Cognito配置 ], session: { strategy: "jwt", }, cookies: { sessionToken: { name: 'next-auth.session-token', domain: 'localhost', // 允许所有localhost下的端口共享这个Cookie path: '/', sameSite: 'lax', secure: false, // 本地http环境设为false,生产环境记得改成true httpOnly: true, }, }, // 其他原有配置... });
2. 自定义Amplify的存储适配器
Amplify允许我们替换默认的存储逻辑,这样就能让Auth模块从next-auth.session-token里解析出Cognito的会话数据。
步骤2.1 解析NextAuth的Session Token
NextAuth的next-auth.session-token是一个JWT,里面包含了Cognito的idToken、accessToken等核心信息,先写工具函数获取并解析它:
// 获取指定名称的Cookie const getCookie = (name) => { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); }; // 解析NextAuth的JWT,提取Cognito令牌信息 const parseNextAuthSession = () => { const sessionToken = getCookie('next-auth.session-token'); if (!sessionToken) return null; // JWT分为三段,中间的是payload,base64解码 const payload = sessionToken.split('.')[1]; // 处理base64可能的填充问题 const decodedPayload = JSON.parse(atob(payload.padEnd(payload.length + (4 - payload.length % 4) % 4, '='))); return { idToken: decodedPayload.idToken, accessToken: decodedPayload.accessToken, refreshToken: decodedPayload.refreshToken, expiresIn: decodedPayload.expiresAt - Date.now() / 1000, // 转成秒数 tokenType: 'Bearer' }; };
步骤2.2 实现Amplify兼容的自定义存储类
Amplify Auth会查找特定格式的存储key,我们需要实现一个存储类,把解析后的NextAuth会话数据映射成Amplify需要的格式:
class CustomAuthStorage { async getItem(key) { const sessionData = parseNextAuthSession(); if (!sessionData) return null; // 替换成你的Cognito Web客户端ID const clientId = "XXXXXXXXXXXXXXXXXXXXXXXXXX"; // 从idToken里提取用户名 const idTokenPayload = JSON.parse(atob(sessionData.idToken.split('.')[1])); const username = idTokenPayload.username; // 根据Amplify需要的key返回对应数据 switch(key) { case `CognitoIdentityServiceProvider.${clientId}.LastAuthUser`: return username; case `CognitoIdentityServiceProvider.${clientId}.${username}.idToken`: return sessionData.idToken; case `CognitoIdentityServiceProvider.${clientId}.${username}.accessToken`: return sessionData.accessToken; case `CognitoIdentityServiceProvider.${clientId}.${username}.refreshToken`: return sessionData.refreshToken; case `CognitoIdentityServiceProvider.${clientId}.${username}.tokenScopesString`: return 'email profile openid'; // 对应你的OAuth scope case `CognitoIdentityServiceProvider.${clientId}.${username}.expiresIn`: return sessionData.expiresIn.toString(); default: return null; } } // 因为我们不需要修改会话,以下方法可以空实现 async setItem(key, value) {} async removeItem(key) {} async clear() {} }
步骤2.3 把自定义存储配置到Amplify
修改你的Amplify配置,用自定义存储替换默认的cookieStorage:
Amplify.configure({ region: "eu-west-1", userPoolId: "eu-west-1_XXXXXXXXX", userPoolWebClientId: "XXXXXXXXXXXXXXXXXXXXXXXXXX", // OAuth配置可以保留,但核心认证逻辑已经通过NextAuth完成 oauth: { domain: "XXXXXXXXXXX.auth.eu-west-1.amazoncognito.com", scope: ['email', 'profile', 'openid'], redirectSignIn: "http://localhost:4200/", redirectSignOut: "http://localhost:3000/", responseType: 'token', }, // 指定自定义存储 storage: new CustomAuthStorage() }); // 现在再调用Auth.currentSession()应该就能拿到会话了 Auth.currentSession() .then((response) => { console.log('response=', response); }) .catch((error) => { console.error('error=', error); });
3. 关键注意事项
- 跨域Cookie验证:确保NextAuth的Cookie设置了
domain: 'localhost',否则不同端口的应用无法共享Cookie。 - JWT解码兼容:如果遇到base64解码错误,记得处理填充问题(代码里已经加了padEnd处理)。
- 存储key匹配:Amplify的存储key格式是固定的,一定要替换成你自己的Cognito客户端ID,否则会匹配失败。
内容的提问来源于stack exchange,提问作者John Fisher
相关产品推荐
相关产品推荐

