如何在浏览器中跨页面保留 Cognito 身份

How to persist Cognito identity across pages in browser

我正在客户端浏览器上使用开发人员身份验证通过 Cognito 进行身份验证。当我的页面加载(或刷新)时,我希望我的应用程序记住身份,只要对象没有过期(我认为它持续大约一个小时)。但是,我不知道如何在无需再次通过开发人员身份验证的情况下从 Cognito 检索身份。

这是代码在页面加载时执行的操作:

var cognitoCredentials

$(document).ready(function() { 
    "use strict";

    cognitoParams = {
      IdentityPoolId: 'us-east-1:xxxxxxx'
    };

    cognitoCredentials = new AWS.CognitoIdentityCredentials(cognitoParams);
    AWS.config.credentials = cognitoCredentials;

});

并通过开发者认证登录后:

cognitoCredentials.params.IdentityId = output.identityId;
cognitoCredentials.params.Logins = {
    'cognito-identity.amazonaws.com': output.token
};
cognitoCredentials.expired = true;

如果我已经登录,然后刷新页面,并尝试再次登录,我会收到一个错误,提示我在已经拥有一个身份的情况下尝试获取一个身份 Error: Missing credentials in config(…) NotAuthorizedException: Missing credentials in config "Access to Identity 'us-east-1:xxxxxxx' is forbidden."

但是,我不知道如何访问它。如何检索凭据以便在刷新页面时可以检测到 Cognito 提供的先前身份?

在页面刷新时返回相同身份的唯一方法是使用用于初始化该身份的相同令牌。您可能需要参考 ,因为问题很相似(将 Facebook 令牌替换为开发人员身份验证流程中的 OpenId Connect 令牌)。

重申一下那个问题的意思:SDK 中的凭据不会跨页面保留,因此您应该缓存令牌以供重复使用。

在页面之间 sessionStorage 中至少保存 accessKeyId, secretAccessKey, sessionToken。您可以将它们加载到 AWS.config.credentials(当然是在加载 AWS SDK 之后)。这比等待 Cognito 响应要快得多。请记住,您必须使用来自提供商之一的令牌手动刷新它们,这仅在临时令牌过期(约 1 小时)之前有效。

var credKeys = [
    'accessKeyId',
    'secretAccessKey',
    'sessionToken'
];

// After Cognito login
credKeys.forEach(function(key) {
    sessionStorage.setItem(key, AWS.config.credentials[key]);
});

// After AWS SDK load

AWS.config.region = 'us-east-1'; // pick your region

credKeys.forEach(function(key) {
    AWS.config.credentials[key] = sessionStorage.getItem(key);
});

// Now make your AWS calls to S3, DynamoDB, etc

我采用了一种稍微不同的方法,允许 SDK 刷新凭据。

简而言之,我将AssumeRoleWithWebIdentityRequest JSON 对象序列化到会话存储中。

这是一个使用 Angular 的示例,但概念适用于任何 JS 应用程序:

const AWS = require('aws-sdk/global');
import { STS } from 'aws-sdk';

import { environment } from '../../environments/environment';

const WEB_IDENT_CREDS_SS_KEY = 'ic.tmpAwsCreds';

// Handle tmp aws creds across page refreshes
const tmpCreds = sessionStorage.getItem(WEB_IDENT_CREDS_SS_KEY);
if (!!tmpCreds) {
  AWS.config.credentials = new AWS.WebIdentityCredentials(JSON.parse(tmpCreds));
}

@Injectable({
  providedIn: 'root'
})
export class AuthService {

...

  async assumeAwsRoleFromWebIdent(fbUser: firebase.User) {
    const token = await fbUser.getIdToken(false);
    let p: STS.Types.AssumeRoleWithWebIdentityRequest = {
      ...environment.stsAssumeWebIdentConfig,
      //environment.stsAssumeWebIdentConfig contains:
      //DurationSeconds: 3600,
      //RoleArn: 'arn:aws:iam::xxx:role/investmentclub-fbase-trust',
      RoleSessionName: fbUser.uid + '@' + (+new Date()),
      WebIdentityToken: token
    };

    // Store creds across page refresh, duno WTF `new AWS.WebIdentityCredentials(p)` don't have an option for this
    AWS.config.credentials = new AWS.WebIdentityCredentials(p);
    sessionStorage.setItem(WEB_IDENT_CREDS_SS_KEY, JSON.stringify(p));
  }

  removeAwsTempCreds() {
    AWS.config.credentials = {};
    sessionStorage.removeItem(WEB_IDENT_CREDS_SS_KEY);
  }

...

注意事项:

  • 登录后,我将 WebIdentityCredentials 参数作为 JSON 字符串存储在会话缓存中。
  • 你会注意到我检查了全局范围内的浏览器会话缓存,以 处理页面刷新(在使用前设置信用)。

可以在 my blog

上找到包含完整示例的教程