[Java] AWS Cognito のユーザーリストを取得する方法

2021-10-10JavaAWS

AWS CognitoIdentityProvider を使ってユーザーリストを取得。 AWS には何かと制限値が設けられているが、Cognito も例外ではなく、場面によっては工夫が必要になりそう。

環境

AWS SDK for Java V2

Gradle プロジェクト

dependencies {
 implementation platform('software.amazon.awssdk:bom:2.16.60')
 implementation group: 'software.amazon.awssdk', name: 'cognitoidentityprovider'
 ...
}

ListUsers

Amazon Cognito User Pool の全ユーザーを取得する方法。ListUsers を使う。

public List<UserType> getListUsers() {
    
    List<UserType> users = new ArrayList<>();
    getListUsers(null, users);
    
    return users;
}
        
List<UserType> getListUsers(String paginationToken, List<UserType> users) {
    
    // リクエスト生成
    ListUsersRequest request;
    if (paginationToken == null) {
        request = ListUsersRequest.builder().userPoolId("USERPOOL_ID").build();
    } else {
        request = ListUsersRequest.builder().userPoolId("USERPOOL_ID").paginationToken(paginationToken).build();
    }
    
    // レスポンス取得
    ListUsersResponse response = cognitoIdentityProvider.listUsers(request);
    // 結果を格納
    users.addAll(response.users());
    
    if (response.paginationToken() != null) {
        return getListUsers(response.paginationToken(), users);
    } else {
        return users;
    }
}

1 回のリクエストにつき 60 件しか結果が返ってこない。

Identity pools (federated users) resource quotas
Maximum number of results from a single list or lookup call  60

https://docs.aws.amazon.com/cognito/latest/developerguide/limits.html#operation-quotas

レスポンスには、 PaginationToken というパラメータが含まれていて、 PaginationToken でリストに続きがあるかどうかを判断できる。全件取得するには、 PaginationToken を使って再帰処理する。

ただし、ListUsers, ListUsersInGroup は、30 リクエスト/秒の制限がある。リクエスト数が制限値を超えると TooManyRequestsException が発生する。

CategoryOperationQuotas

そのため、 1 秒あたり取得できる最大ユーザー数は 60 ユーザー/ リクエスト × 30 リクエスト/秒 = 1800 ユーザー/秒 となる。それ以上のユーザー取得が必要な場合には、 sleep しながらリクエスト送信するとか、後述するグルーピングなどの工夫が必要になる。

ListUsersInGroup

グループを指定して、グループの全ユーザーを取得する方法。 ListUsersInGroup を使う。
ユーザーは事前にグループに追加しておく。

public List<UserType> getListUsersInGroup(String groupName) {
    
    List<UserType> users = new ArrayList<>();
    getListUsersInGroup(groupName, null, users);
    
    return users;
}

List<UserType> getListUsersInGroup(String groupName, String nextToken, List<UserType> users) {
    
    // リクエスト生成
    ListUsersInGroupRequest request;
    if (paginationToken == null) {
        request = ListUsersInGroupRequest.builder().userPoolId("USERPOOL_ID").groupName(groupName).build();
    } else {
        request = ListUsersInGroupRequest.builder().userPoolId("USERPOOL_ID").groupName(groupName).nextToken(nextToken).build();
    }
    
    // レスポンス取得
    ListUsersInGroupResponse response = cognitoIdentityProvider.listUsersInGroup(request);
    // 結果を格納
    users.addAll(response.users());
    
    if (response.nextToken() != null) {
        return getListUsersInGroup(groupName, response.nextToken(), users);
    } else {
        return users;
    }
}

さいごに

AWS Cognito Pool から、1 度にたくさんのデータを取ってこようとしない方がいい。

Posted by Agopeanuts