Я пытаюсь создать базовый веб-сайт (без сервера на AWS), который позволил бы посетителям входить в систему с помощью Google и / или Facebook. В настоящее время я планирую использовать S3, Cognito с федеративными удостоверениями, API Gateway, Lambda (NodeJS) с DynamoDB. Клиентское приложение будет использовать Angular.

У меня работает социальный вход с Google и Facebook, и в настоящее время я вставляю строку в таблицу «пользователи», когда пользователь входит в систему в первый раз, которая включает когнитивный идентификатор, имя, URL-адрес изображения профиля и т. Д.

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

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

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

Ближе всего к этому посту я пришел, но нигде не могу найти токен доступа: Как получить атрибуты пользователя (имя пользователя, адрес электронной почты и т. д.) с помощью идентификатора когнитивного идентификатора

В этом сообщении указано, что я могу использовать GetUser, но я снова не знаю, откуда берется AccessToken: создание пользователя с помощью AWSognito Identity

Если мне нужно использовать GetUser и AccessToken, откуда они берутся и как их сгенерировать? Это исходит от клиента, или я могу получить его в Lambda с помощью AWS.config.credentials?

Я уже некоторое время пытаюсь понять это, и мне кажется, что я упускаю что-то действительно простое!

15
flyingMonkeys 27 Дек 2016 в 06:23
Если вы не получите электронное письмо от пользователя и не отправите его в Cognito, он его не получит. Вам нужно получить от пользователей все, что вам нужно, и хранить в Cognito.
 – 
Sinan Gedik
4 Янв 2017 в 01:54
Есть ли у кого-нибудь ответ? Я столкнулся с той же проблемой.
 – 
Joseph Bolade Caxton-Idowu
4 Апр 2017 в 21:37
Есть ли у кого-нибудь ответ? Я столкнулся с той же проблемой. Проблема здесь в том, что используется федеративная идентификация пользователя, а НЕ когнитивный пул пользователей. Поскольку федеративная идентификация общается с провайдером, таким как Facebook, вы ожидали, что адрес электронной почты пользователя будет где-то храниться в aws. Или он должен быть настраиваемым ,,,, Пока не могу найти это ни в одной документации ....
 – 
Joseph Bolade Caxton-Idowu
4 Апр 2017 в 21:46

3 ответа

Во-первых, войдите в провайдер Cognito Identity (в консоли Cognito) и убедитесь, что ваш провайдер «Область авторизации» подходит. Например, если вы щелкнули по провайдеру Google, вашей областью авторизации может быть «openid электронной почты профиля». Объем зависит от поставщика, но независимо от того, какой объем вы используете, он должен обеспечивать доступ к электронной почте пользователей.

Когда ваш пользователь входит в систему с помощью внешнего поставщика удостоверений (скажем, Facebook), Cognito ведет переговоры с Facebook, а затем вызывает ваш URL-адрес обратного вызова, который задается в разделе «Настройки клиента приложения» консоли Cognito. Этот обратный вызов содержит параметр под названием «код» - параметр задается в URL-адресе обратного вызова, сделанного моим Cognito. Код представляет собой токен OAuth.

Теперь у вас есть токен OAuth в вашем клиенте, который вам нужно отправить POST в Конечная точка AWS Token. Конечная точка токена возвращает три новых токена в ответе; токен JWT ID, токен доступа JWT и токен обновления. Возьмите атрибут id_token из ответа конечной точки. Разберите этот id_token как строку json и возьмите элемент «email». Теперь у вас должен быть адрес электронной почты пользователя.

Вот мой рабочий пример на Java. Это сервлет, который вызывается функцией обратного вызова Cognito.

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
import com.nimbusds.jwt.SignedJWT;
import net.minidev.json.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;

public class CognitoLandingServlet extends HttpServlet {

    static final Logger LOG = LoggerFactory.getLogger(CognitoLandingServlet.class);
    private static final long serialVersionUID = 1L;

    public CognitoLandingServlet() {
        super();
    }

    @Override
    protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {

        // Get the OpenID Connect (OAuth2) token passed back from the hosted Cognito
        // Login Page
        final String code = request.getParameter("code");
        LOG.debug(String.format("Cognito OAuth2 code received from Cognito: %s.", code));

        if (code != null) {
            // do nothing, we have a code as expected
        } else {
            LOG.debug(String.format(
                    "Landing page requested without a Cognito code, the request probably didn't come from Cognito"));
            // we dont have a token so redirect the user to the application sign in
            // page
            request.getRequestDispatcher("/signin").forward(request, response);
        }
        // Exchange the OIDC token for Cognito Access and ID JWT tokens using AWS
        // Token
        // Endpoint
        // There does not appear to be a Java SDK to handle this :(
        final String cognitoClientId = System.getProperty("CognitoClientId");
        final String redirectUri = System.getProperty("CognitoCallBackUrl");
        final String awsTokenEndpoint = System.getProperty("AwsTokenEndpoint");
        final String jwt = swapOauthForJWT(cognitoClientId, code, redirectUri, awsTokenEndpoint);
        // Complete the login using the JWT token string
        loginWithJWT(jwt, request, response);
    }

    @Override
    protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
            throws ServletException, IOException {

    }

    private void loginWithJWT(final String jwtString, final HttpServletRequest request,
                              final HttpServletResponse response) {

        final JSONParser parser = new JSONParser();
        SignedJWT signedIdJWT;

        try {
            // Take the id token
            final JSONObject json = (JSONObject) parser.parse(jwtString);
            final String idToken = (String) json.get("id_token");

            // Access token is not currently used
            // String accessToken = (String) json.get("access_token");

            // Process the id token
            signedIdJWT = SignedJWT.parse(idToken);
            final String userId = signedIdJWT.getJWTClaimsSet().getSubject();

            // Start NEW Session and start adding attributes
            final HttpSession session = request.getSession(true);
            session.setAttribute("userId", userId);

            final String cognitoUsername = (String) signedIdJWT.getJWTClaimsSet()
                    .getClaim("cognito:username");
            if (cognitoUsername != null) {
                user.setUserName(cognitoUsername);
                session.setAttribute("username", cognitoUsername);
            }
            final String email = (String) signedIdJWT.getJWTClaimsSet().getClaim("email");
            if (email != null) {
                user.setEmail(email);
                session.setAttribute("email", email);
            }
            // Save the user to a database (code removed for stack overflow)

            //request.getRequestDispatcher("/dashboard").forward(request, response);
            response.sendRedirect("/dashboard");

            LOG.info(
                    String.format("A user with userid %s and email %s successfully signed in", userId, email));

        } catch (final java.text.ParseException e) {
            LOG.error(
                    String.format("The JWT token could not be parsed by JOSE library. %s", e.getMessage()));
        } catch (final ParseException e) {
            LOG.error(String.format("The JWT token could not be parsed by JSON simple library. %s",
                    e.getMessage()));
        } catch (final IOException e) {
            LOG.error(String.format("Failed to request webpage at the end of the login process - io. %s",
                    e.getMessage()));
        }
    }

    private String swapOauthForJWT(final String cognitoClientId, final String oauthCode,
                                   final String redirectUri, final String awsTokenEndpoint) throws IOException {

        // Build the URL to post to the AWS Token Endpoint
        final String urlParameters = String.format(
                "Content-Type=application/x-www-form-urlencoded&grant_type=authorization_code&client_id=%s&code=%s&redirect_uri=%s",
                cognitoClientId, oauthCode, redirectUri);
        LOG.debug(String.format("User is swapping OAuth token for a JWT using URL %s", urlParameters));
        final URL url = new URL(awsTokenEndpoint);
        final URLConnection conn = url.openConnection();
        conn.setDoOutput(true);
        final OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
        writer.write(urlParameters);
        writer.flush();
        // Read the data returned from the AWS Token Endpoint
        final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        final StringBuilder responseStrBuilder = new StringBuilder();
        String inputStr;
        while ((inputStr = reader.readLine()) != null) {
            responseStrBuilder.append(inputStr);
        }
        // Close the connection
        writer.close();
        reader.close();
        LOG.debug(String.format("Finished swapping OAuth token for a JWT"));

        return responseStrBuilder.toString();
    }
}
4
F_SO_K 21 Янв 2018 в 13:15

Вам также необходимо добавить сопоставления атрибутов в пул пользователей. Проверьте, не забыли ли вы добавить сопоставления. Вы можете найти вкладку «сопоставления атрибутов» в разделе «федерация» в настройках пула пользователей.

2
Sobhan Jachuck 8 Ноя 2018 в 07:51
Не уверен, что официальная документация Cognito достаточно подробно описывает этот шаг. Мы забыли сделать это и потратили несколько часов на отладку.
 – 
TheBrockEllis
8 Апр 2020 в 22:26

Чтобы получить электронное письмо, вы должны запросить его у поставщика удостоверений (facebook, google, пул пользователей).

Чтобы получить электронное письмо из пула пользователей, вам нужно сделать что-то вроде:

cognitoUser.getUserAttributes(function(err, result) {
    if (err) {
        alert(err);
        return;
    }
    for (i = 0; i < result.length; i++) {
        console.log('attribute ' + result[i].getName() + ' has value ' + result[i].getValue());
    }
});

Cognito Identity не сохраняет электронные письма.

0
Ricardo Gamboa 7 Апр 2017 в 02:32