You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

借助AWS JS SDK实现Cognito SSO弹窗登录及令牌存储

Cognito弹窗式SSO登录及令牌存储问题解决方案

问题描述

原始需求

我有一个配置了客户提供的Google身份提供商(IDP)的Cognito用户池,无法获取该IDP的详细信息或访问权限。目前能拿到的Cognito登录URL是:

https://<my-user-pool-url>/oauth2/authorize?identity_provide=<idp-name>&redirect_uri=<my-app-url>&response_type=TOKEN&client_id=<cognito_pool_id>

我不想让用户被重定向到这个URL再跳转回应用,希望通过弹窗让用户用Google IDP登录,从弹窗获取令牌后完成Cognito登录,或者让Cognito自动打开弹窗实现该流程,能否通过AWS JavaScript SDK实现?

我试过一种临时方案,但浏览器会阻止跨源访问弹窗地址,方案代码如下:

const popup = window.open(
    '<cognito_login_url_with_redirect>',
    'popup',
    'popup=true'
  );

  const checkPopup = setInterval(() => {
    if (!popup || popup.closed) return;
    if (popup.window.location.href.includes('<my_redirect_url>')) {
      popup.close();
    }
    clearInterval(checkPopup);
    const access_token = new URLSearchParams(popup.location.search).get(
      'access_token'
    );
    console.log(access_token);
  }, 1000);

我不想用这个方案,也不想自行管理弹窗或跨域使用postMessage,有没有办法无需重定向URI通过SSO登录Cognito?

更新1:令牌存储与认证问题

我已经成功打开弹窗并把access token传回应用,但现在卡在前端如何用这个Cognito令牌完成认证。我用的是amazon-cognito-identity-js和aws-sdk,需要通过access token登录并把所有令牌存到Cookie里,该怎么做?

我的代码如下:

const STORAGE = new CookieStorage({
  domain: WEB_DOMAIN,
  expires: 60,
  secure: true
});
const poolData = {
  UserPoolId: userPoolId,
  ClientId: clientId,
  Storage: STORAGE
};
const COGNITO_USER_POOL = new CognitoUserPool(poolData);
const userData = {
  Username: '<my_user_name>',
  Pool: COGNITO_USER_POOL
};
const authDetails = new AuthenticationDetails({
  Username: '<my_user_name>',
  AccessToken: accessToken
});

这段代码抛出错误:NotAuthorizedException: User is not authorized to get auth details.

我还考虑过获取code而非token,再用它获取所有令牌(access、id、refresh),但不知道怎么用它完成登录并存储Cookie(不能直接存,因为需要LastAuthUser)。请问如何用access_token或其他令牌完成登录,正确存储到Cookie中并让COGNITO_USER_POOL.getCurrentUser()生效?


解决方案

一、合规实现弹窗式SSO登录

Cognito官方JS SDK没有直接封装弹窗式SSO,但可以通过调整OAuth流程配合Hosted UI实现,无需自行处理跨域问题:

  • 将你的应用域名添加到Cognito用户池客户端的允许回调URL和允许退出URL列表
  • 使用response_type=CODE发起授权请求,在弹窗中打开Hosted UI授权URL,回调到应用内的空白页面(如/auth/callback)
  • 空白回调页面通过URL参数拿到code,用postMessage传给父窗口后关闭弹窗
  • 父窗口拿到code后,调用Cognito的POST /oauth2/token接口换取完整令牌(access_token、id_token、refresh_token)

二、用已获取的access_token完成认证并存储令牌

你之前的错误是因为AuthenticationDetails仅用于用户名密码登录,不能直接传入access_token。正确做法是手动构造CognitoUserSession并绑定到CognitoUser实例,令牌会自动存入你配置的CookieStorage:

const STORAGE = new CookieStorage({
  domain: WEB_DOMAIN,
  expires: 60,
  secure: true
});
const poolData = {
  UserPoolId: userPoolId,
  ClientId: clientId,
  Storage: STORAGE
};
const COGNITO_USER_POOL = new CognitoUserPool(poolData);

// 假设已获取到access_token、id_token、refresh_token
const accessToken = new CognitoAccessToken({ AccessToken: '<你的access_token>' });
const idToken = new CognitoIdToken({ IdToken: '<你的id_token>' });
const refreshToken = new CognitoRefreshToken({ RefreshToken: '<你的refresh_token>' });

// 构造用户会话
const userSession = new CognitoUserSession({
  AccessToken: accessToken,
  IdToken: idToken,
  RefreshToken: refreshToken
});

// 从id_token解析用户名(也可从弹窗回调中直接获取)
const username = idToken.payload.username;

// 创建CognitoUser实例
const cognitoUser = new CognitoUser({
  Username: username,
  Pool: COGNITO_USER_POOL
});

// 设置会话,令牌自动存入CookieStorage
cognitoUser.setSignInUserSession(userSession);

// 验证生效状态
const currentUser = COGNITO_USER_POOL.getCurrentUser();
if (currentUser) {
  currentUser.getSession((err, session) => {
    if (!err) {
      console.log('认证成功,会话有效:', session);
    }
  });
}

三、授权code换令牌的实现

如果用response_type=CODE拿到授权码,需先换取完整令牌:

// 调用Cognito令牌接口
fetch(`https://<my-user-pool-url>/oauth2/token`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    client_id: '<cognito_client_id>',
    code: '<拿到的授权code>',
    redirect_uri: '<你的回调URL>'
  })
})
.then(res => res.json())
.then(data => {
  // 用返回的令牌构造会话,后续步骤同上述方案
  const accessToken = new CognitoAccessToken({ AccessToken: data.access_token });
  const idToken = new CognitoIdToken({ IdToken: data.id_token });
  const refreshToken = new CognitoRefreshToken({ RefreshToken: data.refresh_token });
  // ...构造会话并绑定到CognitoUser实例
});

关键注意事项

  • 确保回调URL在Cognito用户池客户端的允许列表中,否则会被拦截
  • CookieStorage的domain和secure属性必须与应用域名匹配,否则无法正常存储
  • 弹窗回调页面需与父窗口同域,避免postMessage被浏览器阻止

内容的提问来源于stack exchange,提问作者hido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 08:57:24