能否使用AWS Cognito令牌实现多应用间用户免重复登录验证?
AWS Cognito 同域名子路径应用跨应用免登录实现方案
核心逻辑
你的场景下所有应用都属于user.myappsite.com顶级域名下的子路径,浏览器会共享该域名下的Cookie。只要将Cognito登录生成的令牌存储在顶级域名的Cookie中,所有子路径应用就能读取并验证令牌,实现免重复登录。
具体实现步骤
1. 统一Cognito应用客户端配置
- 所有子路径应用必须使用同一个Cognito用户池的同一个应用客户端
- 在应用客户端设置中,将
Allowed Callback URLs和Allowed Sign-out URLs覆盖所有子路径,例如:https://user.myappsite.com/app1/callbackhttps://user.myappsite.com/app2/callbackhttps://user.myappsite.com/app3/callback
- 可选开启
Enable Token Revocation,用于安全注销令牌
2. 登录时存储令牌到顶级域名Cookie
登录成功后,将Cognito返回的令牌写入顶级域名Cookie,确保所有子路径可访问:
// 登录成功后获取Cognito会话令牌 const tokens = await cognitoUser.getSession(); // 设置Cookie,domain指定为顶级域名,path设为根路径 document.cookie = `id_token=${tokens.getIdToken().getJwtToken()}; domain=.user.myappsite.com; path=/; secure; HttpOnly; SameSite=Lax`; document.cookie = `access_token=${tokens.getAccessToken().getJwtToken()}; domain=.user.myappsite.com; path=/; secure; HttpOnly; SameSite=Lax`; document.cookie = `refresh_token=${tokens.getRefreshToken().getToken()}; domain=.user.myappsite.com; path=/; secure; HttpOnly; SameSite=Strict`;
Secure:仅在HTTPS下传输Cookie,生产环境必须启用HttpOnly:防止JS读取Cookie,降低XSS风险(若前端无需直接操作令牌,建议开启)SameSite:控制跨站Cookie传输,Lax适合大多数场景
3. 子路径应用的令牌验证流程
每个应用初始化时,先读取Cookie中的令牌并验证有效性:
// 从Cookie中提取id_token const getCookie = (name) => document.cookie.split('; ').find(row => row.startsWith(`${name}=`))?.split('=')[1]; const idToken = getCookie('id_token'); const accessToken = getCookie('access_token'); if (idToken) { // 验证令牌是否过期 const isExpired = () => { const payload = JSON.parse(atob(idToken.split('.')[1])); return payload.exp * 1000 < Date.now(); }; if (!isExpired()) { // 验证JWT签名(使用Cognito公钥) const verifyToken = async () => { const region = '你的AWS区域'; const userPoolId = '你的用户池ID'; const jwksRes = await fetch(`https://cognito-idp.${region}.amazonaws.com/${userPoolId}/.well-known/jwks.json`); const jwks = await jwksRes.json(); const header = JSON.parse(atob(idToken.split('.')[0])); const publicKey = jwks.keys.find(key => key.kid === header.kid); // 这里需要引入JWT验证库(如jsonwebtoken) return jwt.verify(idToken, publicKey, { algorithms: ['RS256'] }); }; try { await verifyToken(); // 令牌有效,直接加载用户状态 const userInfo = JSON.parse(atob(idToken.split('.')[1])); // 处理登录逻辑 } catch (err) { // 令牌无效,跳转登录页 window.location.href = '/login'; } } else { // 令牌过期,使用refresh_token刷新 const refreshTokens = async () => { const refreshToken = getCookie('refresh_token'); const cognitoUser = new AmazonCognitoIdentity.CognitoUser({ Username: '用户名', // 可从id_token payload中获取 Pool: userPool }); cognitoUser.refreshSession(refreshToken, (err, newSession) => { if (!err) { // 更新Cookie中的令牌 document.cookie = `id_token=${newSession.getIdToken().getJwtToken()}; domain=.user.myappsite.com; path=/; secure; HttpOnly; SameSite=Lax`; document.cookie = `access_token=${newSession.getAccessToken().getJwtToken()}; domain=.user.myappsite.com; path=/; secure; HttpOnly; SameSite=Lax`; // 刷新页面或加载用户状态 } else { // 刷新失败,跳转登录 window.location.href = '/login'; } }); }; await refreshTokens(); } } else { // 无令牌,跳转登录页 window.location.href = '/login'; }
4. 统一注销流程
注销时需清除顶级域名下的令牌Cookie,并调用Cognito注销接口:
// 调用Cognito注销 cognitoUser.signOut(); // 清除所有令牌Cookie const clearCookie = (name) => { document.cookie = `${name}=; domain=.user.myappsite.com; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC`; }; clearCookie('id_token'); clearCookie('access_token'); clearCookie('refresh_token'); // 跳转至登录页或首页 window.location.href = '/login';
关键注意事项
- 所有应用必须使用相同的用户池和应用客户端ID,否则令牌无法跨应用验证
- 必须使用HTTPS协议,
SecureCookie仅在HTTPS下生效,且Cognito登录流程强制要求HTTPS - 若启用
HttpOnlyCookie,前端无法直接读取令牌,需通过后端接口处理令牌验证逻辑 - 定期刷新令牌:
access_token默认有效期1小时,需在过期前自动调用刷新接口
内容的提问来源于stack exchange,提问作者dcp3450
相关产品推荐
相关产品推荐

