【问题标题】:JAVA- AWS Cognito -Check if a user exists in Cognito User poolJAVA- AWS Cognito -检查用户是否存在于 Cognito 用户池中
【发布时间】:2021-02-04 17:08:26
【问题描述】:

我想允许用户在字段中输入他们的用户名/密码。继续后,我想检查该用户是否已存在于用户池中。如果有,请登录并继续使用应用程序,如果没有,请转到帐户创建流程,指示他们添加姓名、电话号码、电子邮件等。

我找不到有关如何使用 AWS Cognito 登录用户的文档。我应该能够在通话中传递用户名/密码并得到回复说用户存在/用户不存在或其他什么!我在这里遗漏了什么吗?

任何帮助将不胜感激。我已经搜索了文档...

【问题讨论】:

  • 您是否使用社交登录(即 Facebook、Google 等)?您使用的是什么版本的 SDK?你有多少用户?传递用户名/密码以确定帐户是否存在是一个巨大的安全漏洞,因为它允许任何人找出有效的用户名。
  • 没有非社交登录。我们有一个应用程序,用户通过提供用户名和密码登录,现在正在从 mySQL 数据库进行身份验证。但现在我们想将用户从 mySQL 数据库移动到 Cognito 用户池。但是,每个用户都会有一个关联的电子邮件链接到他们的帐户。截至目前,我们有大约 2 万名用户。因此,为了不要求每个用户重置密码。
  • 我想一次关注这个迁移用例,其中用户将尝试登录我们的应用程序,然后我们尝试从用户池中对用户进行身份验证。如果用户池中没有这样的用户,那么它会针对 mySQl 进行身份验证,如果成功则将该用户迁移到用户池

标签: java authentication aws-lambda amazon-cognito aws-userpools


【解决方案1】:

要检查用户是否存在,您只需要用户名即可。

所以对于你的场景,在用户输入用户名和密码后触发下面的myMethod()。那会

  1. 检查用户名是否已经在用户中
  2. 如果用户名存在,则执行登录
  3. 如果用户名不存在,则创建帐户

/**
* let's say you call this method when user enters username and password
* @param context context
* @param identityProvider cognito client
* @param username user entered username
* @param password user entered password
* @return
*/
private void myMethod(Context context, AWSCognitoIdentityProvider identityProvider, String username, String password) {
    
    boolean userExists = userExists(context, identityProvider, username);
    
    if(userExists) {
        // perform sign in with provided password
    } else {
        // create account
    }
}


/**
* @param context context
* @param identityProvider cognito client
* @param username user entered username
* @return true if username is already in use, false otherwise
*/
private boolean userExists(Context context, AWSCognitoIdentityProvider identityProvider, String username) {
    LambdaLogger logger = context.getLogger();

    try {
        AdminGetUserRequest getUserRequest = new AdminGetUserRequest();
        getUserRequest.setUserPoolId("cognitoPoolId");
        getUserRequest.setUsername(username);

        AdminGetUserResult getUserResult = identityProvider.adminGetUser(getUserRequest);

        return true;
    } catch (UserNotFoundException userNotFoundException) {
        logger.log("UserNotFoundException! " + userNotFoundException.toString());
        return false;
    } catch (Exception e) {
        return false;
    }
}

【讨论】:

    【解决方案2】:

    我不必每次都对您的 Cognito 用户池进行全面扫描,而是使用 Cognito 的功能来触发事件。对于您的用例,Cognito 可以运行 Lambda。您对Migrate User 触发器感兴趣。基本上发生的情况是,当用户尝试通过 Cognito 登录您的系统时,该用户在池中不存在,触发触发器让您登录用户并将其迁移到 Cognito .

    传入的数据如下:

    {
        "version": "1",
        "triggerSource": "UserMigration_Authentication",
        "region": "us-west-2",
        "userPoolId": "us-west-2_abcdef",
        "userName": "theusername@example.com",
        "callerContext": {
            "awsSdkVersion": "aws-sdk-unknown-unknown",
            "clientId": "yourclientid"
        },
        "request": {
            "password": "theuserpassword",
            "validationData": null,
            "userAttributes": null
        },
        "response": {
            "userAttributes": null,
            "forceAliasCreation": null,
            "finalUserStatus": null,
            "messageAction": null,
            "desiredDeliveryMediums": null
        }
    }
    

    您的 Lambda 将使用它并最终获取用户名和密码并确定它是否有效。如果是,您将在 response.userAttributes 字段中传回信息,以及是否要发送 Cognito 欢迎电子邮件 (messageAction) 和其他一些值。例如,您可以发回:

    {
        "version": "1",
        "triggerSource": "UserMigration_Authentication",
        "region": "us-west-2",
        "userPoolId": "us-west-2_abcdef",
        "userName": "theusername@example.com",
        "callerContext": {
            "awsSdkVersion": "aws-sdk-unknown-unknown",
            "clientId": "yourclientid"
        },
        "request": {
            "password": "theuserpassword",
            "validationData": null,
            "userAttributes": null
        },
        "response": {
            "userAttributes": { "email":"theusername@example.com",
                                "email_verified": "true" }
            "forceAliasCreation": null,
            "finalUserStatus": "CONFIRMED",
            "messageAction": "SUPPRESS",
            "desiredDeliveryMediums": null
        }
    }
    

    您的 Lambda 在 Java 中将如下所示:

    public class MigrateUserLambda implements RequestStreamHandler {
    
        public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
            LambdaLogger logger = context.getLogger();
    
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(inputStream);
    
            logger.log("input is " + objectMapper.writeValueAsString(rootNode));
    
            String email = rootNode.path("email").asText();
            String password = rootNode.path("request").path("password").asText();
    
            // verify user name and password in MySQL.  If ok...
    
            String triggerSource = rootNode.path("triggerSource").asText();
    
            if( triggerSource.equals("UserMigration_Authentication")) {
                JsonNode responseNode = rootNode.path("response");
                if (responseNode != null) {
                    ((ObjectNode) responseNode).with("userAttributes").put("username", "theusername@example.com" );
                    ((ObjectNode) responseNode).with("userAttributes").put("email_verified", "true" );
                    ((ObjectNode) responseNode).put("messageAction", "SUPPRESS");
                    ((ObjectNode) responseNode).put("finalUserStatus", "CONFIRMED");
                }
            }
    
            String output = objectMapper.writeValueAsString(rootNode);
    
            OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
            writer.write(output);
            logger.log("sending back " + output);
    
            writer.close();
        }
    }
    

    【讨论】:

      【解决方案3】:

      要列出用户,您可以使用 AWS Java SDK:

      public static void list() {
          AwsBasicCredentials awsCreds = AwsBasicCredentials.create(AWS_KEY,
                  AWS_SECRET);
      
          CognitoIdentityProviderClient identityProviderClient =
                  CognitoIdentityProviderClient.builder()
                          .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
                          .region(Region.of(REGION))
                          .build();
      
          final ListUsersRequest listUsersRequest = ListUsersRequest.builder()
                  .userPoolId(POOL_ID)
                  .build();
      
          ListUsersResponse result = identityProviderClient.listUsers(listUsersRequest);
      
          System.out.println("Has users:"+result.hasUsers());
          result.users().stream().map(u->u.username()).forEach(System.out::println);
      }
      

      它需要下一个依赖项(请使用最新版本):

      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>aws-core</artifactId>
        <version>2.13.57</version>
      </dependency>
      
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>cognitoidentityprovider</artifactId>
        <version>2.13.57</version>
      </dependency>
      

      Here 是如何从 Java 登录用户的代码示例。

      【讨论】:

      • 此解决方案将不起作用 - ListUsersRequest 一次只能返回 60 个用户。如果你的 cognito 有成百上千的用户,你首先必须做 for 循环(可能数百次)首先获取所有用户。
      • @ᴛʜᴇᴘᴀᴛᴇʟ 你说得对,我没有考虑用户数量,因此提出了一个不好的解决方案。
      猜你喜欢
      • 2021-08-28
      • 2022-01-15
      • 1970-01-01
      • 2017-04-08
      • 1970-01-01
      • 2019-07-02
      • 1970-01-01
      • 2019-04-01
      • 2018-01-31
      相关资源
      最近更新 更多