如何通过集成ALB的AWS Cognito实现多子域用户统一登出?
场景概述
我在EC2上运行一组容器化Web应用,通过NGINX反向代理按子域路由流量:主应用部署在hub.DOMAIN,其他子应用分布在app1.hub.DOMAIN等子域。流量先经过Application Load Balancer(ALB),其默认监听器配置了authenticate-cognito动作,仅转发已认证用户的请求。
所有应用共用同一个AWS Cognito用户池,仅开启用户名密码登录,使用托管登录UI,正常认证流程没问题:未认证用户会被跳转至登录页,仅认证用户可访问应用。
问题描述
在hub.DOMAIN添加登出按钮后,执行以下操作仅对当前子域生效:
- 删除ALB设置的Cognito Cookie
- 跳转至Cognito登出端点
其他子域的用户仍保持登录状态。原本预期Cognito登出端点会使令牌失效,阻止所有子域的访问,但实际ALB会为每个子域生成独立Cookie,只要Cookie存在且令牌未过期,ALB就不会重新校验会话有效性。
尝试调用Cognito的GlobalSignOut API使x-amzn-oidc-accesstoken失效,无报错但仍可访问所有子域页面。推测ALB仅在Cookie不存在或令牌过期时才会触发重新认证,无法跨子域删除Cookie导致登出不彻底;即使将用户池会话时长设为最短5分钟,仍存在5分钟的访问窗口,不符合需求。
核心疑问
如何在用户从任一应用登出后,强制ALB阻止所有子域的流量?此架构下是否可行,还是必须在EC2端通过Cognito API主动校验会话有效性?
解决方案
1. 统一ALB认证Cookie的父域
ALB默认给每个子域生成独立Cookie,修改ALB监听器的authenticate-cognito配置,将Cookie的域设置为父域,让所有子域共用同一个认证Cookie:
- 进入AWS控制台的ALB监听器设置,找到
authenticate-cognito动作的配置项 - 在「Cookie Settings」中设置
Domain为.hub.DOMAIN(注意开头的点,确保所有子域都能共享),同时将Path设为/ - 这样在
hub.DOMAIN登出时删除该Cookie,所有子域的认证状态都会同步失效
2. 配合GlobalSignOut彻底失效令牌
仅删除Cookie不足以阻止用户用旧令牌重新认证,需在登出流程中加入GlobalSignOut调用:
- 使用用户的ID Token或Refresh Token调用Cognito
GlobalSignOutAPI,该API会使用户所有活跃的Refresh Token失效,阻止后续刷新Access Token - 执行顺序:先调用
GlobalSignOut,再删除父域Cookie,最后跳转至Cognito登出端点清理Cognito端会话
3. 应用层兜底校验(可选,实现即时失效)
如果需要完全即时的登出效果(零访问窗口),需在EC2侧添加额外校验:
- 从ALB转发的请求中提取
x-amzn-oidc-accesstoken - 调用Cognito的
GetUser或VerifyTokenAPI校验令牌有效性(注意添加缓存避免性能损耗) - 若令牌已失效,直接返回401并跳转至登录页
关键原理
ALB的authenticate-cognito动作出于性能优化,不会实时校验令牌是否已失效,仅在Cookie缺失或令牌过期时才会触发重新认证。统一父域Cookie解决跨子域会话同步问题,GlobalSignOut从服务器端终止所有会话,应用层校验则实现即时失效的兜底。
内容的提问来源于stack exchange,提问作者GrundSolide

