如何在Cognito联合身份中访问用户的电子邮件地址? [英] How to access user's email address in Cognito Federated Identities?

查看:135
本文介绍了如何在Cognito联合身份中访问用户的电子邮件地址?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试建立一个基本网站(AWS上没有服务器),以允许访问者使用Google和/或Facebook登录。目前,我正计划将S3,具有联合身份的Cognito,API网关,Lambda(NodeJS)与DynamoDB结合使用。客户端应用程序将使用Angular。

I'm trying to set up a basic website (serverless on AWS) that would allow visitors to login with Google and/or Facebook. Currently I'm planning to use S3, Cognito with Federated Identities, API Gateway, Lambda (NodeJS), with DynamoDB. The client app will be using Angular.

我可以使用Google和Facebook进行社交登录,目前,当用户登录时,我正在用户表中插入一行首次登录时包含cognitoId,名称,个人资料图片URL等。

I have the social login with Google and Facebook working, and currently I am inserting a row in a "users" table when a user logs in the first time that includes the cognitoId, name, profile picture URL, etc.

我还认为将用户信息与电子邮件存储在一起是一个很好的设计地址作为键,而不是诸如cognitoId之类的键,以便用户可以使用不同的提供程序登录并查看相同的数据。因此,我需要知道经过身份验证的用户的电子邮件地址,但是我认为它应该来自Cognito,而不是直接来自用户(因为不应该信任客户端应用程序)。

I also figure it would be a good design to store the user's information with their email address as the key, instead of something like the cognitoId so that the user can login using different Providers and see the same data. So I need to know the authenticated user's email address, but I figure it should come from Cognito and not straight from the user (since the client app shouldn't be trusted).

我相信Cognito正在存储用户的电子邮件地址,因为我已根据需要在用户池中启用了该字段。

I believe that Cognito is storing the user's email address because I have enabled that field as required int the User Pool.

我遇到的问题是我无法找到有关如何从Cognito获取用户的电子邮件地址的任何信息。

The issue I'm having is that I cannot find any information about how to get the user's email address from Cognito.

我最近来的是这篇文章,但是我在任何地方都找不到访问令牌。 :如何获取用户属性(用户名,电子邮件等)使用认知身份ID

The closest that I've come is this post, but I can't find the access token anywhere: How to get user attributes (username, email, etc.) using cognito identity id

此帖子表明我可以使用GetUser,但我又不知道AccessToken来自:创建用户使用AWS Cognito身份

This post indicates that I may be able to use GetUser, but I again don't know where the AccessToken comes from: creating user using AWS cognito identity

如果我确实需要使用GetUser和AccessToken,它来自何处以及如何生成?它来自客户端,还是可以使用AWS.config.credentials在Lambda中获得?

If I do need to use GetUser and the AccessToken, where does it come from, and how do I generate it? Does it come from the client, or can I get it in Lambda using AWS.config.credentials?

我已经尝试了一段时间了,现在我感觉好像缺少了一些非常简单的东西!

I've been trying to figure this out for a while now and I'm feeling like I'm missing something really simple!

推荐答案

首先,进入Cognito身份提供程序(在Cognito控制台中) ),并确保您的提供商授权范围合适。例如,如果您单击Google提供者,则您的授权范围可能是个人资料电子邮件openid。范围会因提供商而异,但是无论您使用什么范围,它都必须提供对用户电子邮件的访问权限。

Firstly, go into Cognito Identity provider (in the Cognito console) and make sure your provider "Authorize Scope" is suitable. For example if you clicked on the Google provider your Authorize scope might be "profile email openid". The scope will vary by provider, but whatever scope you are using, it must provide access to the users email.

当您的用户使用外部身份提供商登录时(例如Facebook),Cognito与Facebook协商,然后调用您的Callback URL,该URL在Cognito控制台的应用程序客户端设置部分中设置。该回调包含一个名为代码的参数-该参数在我的Cognito的回调URL中设置。该代码是一个OAuth令牌。

When your user logs in with an external identity provider (lets say Facebook), Cognito negotiates with Facebook and then calls your Callback URL, which is set in the 'App Client Settings' part of the Cognito console. That Callback contains a parameter called 'code' - the parameter is set in the URL of the Callback made my Cognito. The code is an OAuth token.

现在您的客户端中已有一个OAuth令牌,您需要将其发布到 AWS令牌端点。令牌端点返回响应中有三个新令牌; JWT ID令牌,JWT访问令牌和刷新令牌。从端点响应中获取 id_token属性。将该id_token解析为json字符串,然后使用 email元素。现在您应该拥有用户的电子邮件地址。

Now you have an OAuth token in your client you need to POST that to the AWS Token Endpoint. The token endpoint returns three new tokens in the response; a JWT ID Token, a JWT Access Token and a refresh token. Take the "id_token" attribute from the endpoint response. Parse that id_token as a json string, and take the 'email' element. Now you should have the users email address.

这是我在Java中的工作示例。

Here is my working example in Java. This is a servlet that gets called by the Cognito Callback.

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();
    }
}

这篇关于如何在Cognito联合身份中访问用户的电子邮件地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆