Как сохранить идентичность Cognito на страницах в браузере

Я аутентифицируюсь через 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?

Ответ 1

Единственный способ вернуться к одному и тому же идентификатору при обновлении страницы - использовать тот же токен, который используется для инициализации этого идентификатора. Вы можете обратиться к этому вопросу, поскольку проблемы схожи (замена токена Facebook токеном OpenId Connect из потока аутентифицированных идентификаторов разработчика).

Чтобы повторить, что говорит этот вопрос: учетные данные в SDK не будут сохраняться на разных страницах, поэтому вы должны кэшировать токен, который будет повторно использоваться.

Ответ 2

Сохраните не менее accessKeyId, secretAccessKey, sessionToken в sessionStorage между страницами. Вы можете загрузить их в AWS.config.credentials(после загрузки AWS SDK, конечно). Это намного быстрее, чем ждать, когда Когнито ответит. Имейте в виду, вам придется вручную обновить их с помощью токена от одного из поставщиков, и это только хорошо, пока временный токен не истечет (~ 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

Ответ 3

Я использую немного другой подход, который позволяет SDK обновлять учетные данные.

Короче говоря, я сериализую объект JSON AssumeRoleWithWebIdentityRequest в хранилище сеансов.

Вот пример использования 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 в кэше сеанса.
  • Вы заметите, что я проверяю кэш сеанса браузера в глобальной области видимости, чтобы обрабатывать обновления страниц (устанавливает кредиты, прежде чем их можно будет использовать).

Учебное пособие с полным примером можно найти в моем блоге.