Должен ли я объединять пулы пользователей cognito вместе с другими социальными idps или иметь социальный вход через сам пул пользователей - PullRequest
0 голосов
/ 01 февраля 2019

Я создаю приложение для социального чата, и первоначально у меня был пул Cognito, который был объединен с Google / Facebook.Я хранил пользовательские данные, основанные на подпрограмме user для пользователей cognito и идентификаторе личности для google / facebook.Затем в моих средствах разрешения лямбда-gql я бы проходил аутентификацию через AWS-sdk:

  AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: process.env.IDENTITY_POOL_ID,
    Logins: {
      [`cognito-idp.us-east-1.amazonaws.com/${
        process.env.COGNITO_USERPOOL_ID
      }`]: Authorization,
    },
  });

Поскольку все пользователи равны и мне не нужны детальные элементы управления доступом к aws-ресурсам, кажется,вместо этого было бы предпочтительнее вместо этого обрабатывать всю аутентификацию через пул пользователей и полностью избавляться от пула идентификаций.

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

Итак, мои вопросы: 1. Возможно ли это вообще?- https://github.com/aws-amplify/amplify-js/issues/565 - https://www.reddit.com/r/aws/comments/92ye5s/is_it_possible_to_add_googlefacebook_user_to/

Кажется, что есть много путаницы, и документы aws менее ясны, чем обычно (что не так уж много по моему мнению).https://docs.aws.amazon.com/cognito/latest/developerguide/authentication.html

Кажется, что есть способ сделать это.Я следовал приведенному выше руководству и получаю сообщения об ошибках с конечной точкой размещенного пользовательского интерфейса, но это, вероятно, на мне (https://forums.aws.amazon.com/thread.jspa?threadID=262736). Однако я не хочу, чтобы конечная точка размещенного пользовательского интерфейса, я хотел бы, чтобы пользователи cognito входили через мою пользовательскую формуа затем в социальных сетях пользователи нажимают кнопку «продолжить с fb» и автоматически заполняют мой пул пользователей.

Затем замените приведенный выше код следующим кодом для проверки всех пользователей:

const validate = token => new Promise(async (resolve) => {
  const {
    data: { keys },
  } = await axios(url);

  const { sub, ...res } = decode(token, { complete: true });
  const { kid } = decode(token, { header: true });
  const jwk = R.find(R.propEq('kid', kid))(keys);
  const pem = jwkToPem(jwk);
  const response = res && res['cognito:username']
    ? { sub, user: res['cognito:username'] }
    : { sub };
  try {
    await verify(token, pem);
    resolve(response);
  } catch (error) {
    resolve(false);
  }
});
Если это возможно, каков правильный механизм, который заменил бы следующее:
      Auth.federatedSignIn('facebook', { token: accessToken, expires_at }, user)
        .then(credentials => Auth.currentAuthenticatedUser())
        .then((user) => {
          onStateChange('signedIn', {});
        })
        .catch((e) => {
          console.log(e);
        });

Из того, что я видел, похоже, не существует метода с Amplify для этого,Есть ли способ сделать это с помощью aws-sdk?Как насчет сопоставления обратного вызова из API Facebook для создания клиентской части Cognito пользователя?Кажется, что это может стать довольно грязным.

Если нет механизма для выполнения вышесказанного, должен ли я объединять пользователей Cognito с социальными входами?

И что потом использовать для идентификации пользователей в моей базе данных?В настоящее время я использую имя пользователя и саб для cognito и id для федеративных пользователей.Извлечение сабвуфера со стороны токена Auth на стороне сервера, а затем на клиенте:

  Auth.currentSession()
    .then((data) => {
      const userSub = R.path(['accessToken', 'payload', 'sub'], data);
      resolve(userSub);
    })
    .catch(async () => {
      try {
        const result = await Auth.currentCredentials();
        const credentials = Auth.essentialCredentials(result);
        resolve(removeRegionFromId(credentials.identityId));
      } catch (error) {
        resolve(false);
      }
    });

Если кто-нибудь может дать подробный авторитетный ответ, который мне еще предстоит найти в отношении использования пользователя cognitoбассейны вместо федерации это было бы здорово.В противном случае очень хотелось бы получить общее представление о правильном подходе.

1 Ответ

0 голосов
/ 02 февраля 2019

Вот то, что я в конечном итоге сделал для любого в подобной должности, это не исчерпывающе:

  1. Создайте пул пользователей, не указывайте секрет клиента или любые обязательные атрибуты, которые могут конфликтовать с возвращаемым.из Facebook / Google.
  2. В доменах на боковой панели Cognito добавьте то, что вы хотите, чтобы ваше было.
  3. Добавьте свою личность, предоставленную Cognito, для FB вы хотите, чтобы они были запятымиразделены так: openid, phone, email, profile, aws.cognito.signin.user.admin
  4. Включить FB из настроек клиента приложения, выбрать неявное предоставление.Я верю, но не уверен, openid необходим для генерации ключа доступа и signin.user.admin для получения токена RS256 для проверки с открытым ключом.
  5. С консоли разработчика FB, https://yourdomain.auth.us -east-1.amazoncognito.com / oauth2 / idpresponse , как допустимые перенаправления oauth.
  6. Затем, все еще на FB, перейдите в настройки (общие, не специфичные для приложения) и введите https://yourdomain.auth.us -east-1.amazoncognito.com / oauth2 / idpresponse
  7. https://yourdomain.auth.us -east-1.amazoncognito.com / oauth2 / idpresponse для URL вашего сайта.
  8. Затем для кнопки входа в систему вы можете добавить следующий код,
const authenticate = callbackFn => () => {
  const domain = process.env.COGNITO_APP_DOMAIN;
  const clientId = process.env.COGNITO_USERPOOL_CLIENT_ID;
  const type = 'token';
  const scope = 'openid phone email profile aws.cognito.signin.user.admin';
  const verification = generateVerification();
  const provider = 'Facebook';
  const callback = `${window.location.protocol}//${
    window.location.host
  }/callback`;

  const url = `${domain}/authorize?identity_provider=${provider}&response_type=${type}&client_id=${clientId}&redirect_uri=${callback}&state=${verification}&scope=${scope}`;
  window.open(url, '_self');
};
Затем на странице перенаправления:
  useEffect(() => {
    // eslint-disable-next-line no-undef
    if (window.location.href.includes('#access_token')) {
      const callback = () => history.push('/');
      newAuthUser(callback);
    }
  }, []);
/* eslint-disable no-undef */
import { CognitoAuth } from 'amazon-cognito-auth-js';
import setToast from './setToast';

export default (callback) => {
  const AppWebDomain = process.env.COGNITO_APP_DOMAIN;
  // https://yourdomainhere.auth.us-east-1.amazoncognito.com'
  const TokenScopesArray = [
    'phone',
    'email',
    'profile',
    'openid',
    'aws.cognito.signin.user.admin',
  ];
  const redirect = 'http://localhost:8080/auth';
  const authData = {
    ClientId: process.env.COGNITO_USERPOOL_CLIENT_ID,
    AppWebDomain,
    TokenScopesArray,
    RedirectUriSignIn: redirect,
    RedirectUriSignOut: redirect,
    IdentityProvider: 'Facebook',
    UserPoolId: process.env.COGNITO_USERPOOL_ID,
    AdvancedSecurityDataCollectionFlag: true,
  };
  const auth = new CognitoAuth(authData);

  auth.userhandler = {
    onSuccess() {
      setToast('logged-in');
      callback();
    },
    onFailure(error) {
      setToast('auth-error', error);
      callback();
    },
  };

  const curUrl = window.location.href;
  auth.parseCognitoWebResponse(curUrl);
};

Затем вы можете использовать Auth.currentSession () для получения пользовательских атрибутов от клиента.

Затем на стороне сервера вы можете проверить всех пользователей следующим образом:
const decode = require('jwt-decode');
const jwt = require('jsonwebtoken');
const jwkToPem = require('jwk-to-pem');
const axios = require('axios');
const R = require('ramda');
const logger = require('./logger');

const url = `https://cognito-idp.us-east-1.amazonaws.com/${
  process.env.COGNITO_USERPOOL_ID
}/.well-known/jwks.json`;

const verify = (token, n) => new Promise((resolve, reject) => {
  jwt.verify(token, n, { algorithms: ['RS256'] }, (err, decoded) => {
    if (err) {
      reject(new Error('invalid_token', err));
    } else {
      resolve(decoded);
    }
  });
});

const validate = token => new Promise(async (resolve) => {
  const {
    data: { keys },
  } = await axios(url);

  const { sub, ...res } = decode(token, { complete: true });
  const { kid } = decode(token, { header: true });
  const jwk = R.find(R.propEq('kid', kid))(keys);
  const pem = jwkToPem(jwk);
  const response = res && res['cognito:username']
    ? { sub, user: res['cognito:username'] }
    : { sub };
  try {
    await verify(token, pem);

    resolve(response);
  } catch (error) {
    logger['on-failure']('CHECK_CREDENTIALS', error);
    resolve(false);
  }
});

const checkCredentialsCognito = Authorization => validate(Authorization);

...