AWS Cognito,为什么InitiateAuthResponse为null?

huangapple go评论75阅读模式
英文:

AWS Cognito, why InititiateAuthResponse is null?

问题

我第一次在Java中使用AWS Cognito进行开发。

我创建了一个用于管理员创建用户的代码。用户将自动以FORCE_CHANGE_PASSWORD状态创建。接下来我要做的是一个简单的登录,但如果系统返回CHANGE_PASSWORD挑战,那么它将打开另一个窗口,用户应该在其中输入旧密码和新密码,然后将它们提交给Cognito。

我用于通过AdminCreateUser创建用户的代码如下:

// 创建CognitoIdentityProvider客户端实例
CognitoIdentityProviderClient cognitoClient = CognitoIdentityProviderClient.builder().region(Region.EU_CENTRAL_1).build();

AdminCreateUserRequest requestUserCreation = AdminCreateUserRequest.builder()
    .username(usernameTextField.getText())
    .desiredDeliveryMediums(DeliveryMediumType.EMAIL)
    .userAttributes(AttributeType.builder()
        .name("email")
        .value(emailTextField.getText())
        .build())
    .userPoolId("xxxxx")
    .build();

// 发送注册请求
AdminCreateUserResponse responseUserCreation = cognitoClient.adminCreateUser(requestUserCreation);

// 通过组合框保存要将用户放入的组
String groupname = (String) groupComboBox.getValue();

UserType newUser = responseUserCreation.user();
GroupType group = GroupType.builder().groupName(groupname).build();

AdminAddUserToGroupRequest addUserToGroupRequest = AdminAddUserToGroupRequest.builder()
    .userPoolId("xxxxx")
    .username(newUser.username())
    .groupName(groupname)
    .build();

AdminAddUserToGroupResponse addUserToGroupResult = cognitoClient.adminAddUserToGroup(addUserToGroupRequest);

这段代码有效。当我通过按钮提交时,会向我创建的用户发送一封电子邮件,并且还会显示在我的Amazon Cognito控制台中。

现在登录部分让我感到困扰。

正如我所说,我想打开另一个窗口,其中包含重置密码的正确表单。因为我的登录无法工作,所以我还没有考虑重置密码的实现,所以我将稍后实现这部分。

这是我的登录代码:

public void Login(ActionEvent event) {
    final String CLIENT_ID = cs.getAppClientId();
    final String USER_NAME = userNameTextField.getText();
    final String PASSWORD = passwordTextField.getText();
    final Region region = cs.getRegion();

    CognitoIdentityProviderClient cognitoClient = CognitoIdentityProviderClient.builder()
        .credentialsProvider(DefaultCredentialsProvider.create())
        .region(region)
        .build();

    InitiateAuthRequest authRequest = InitiateAuthRequest.builder()
        .clientId(CLIENT_ID)
        .authFlow("USER_PASSWORD_AUTH")
        .authParameters(createAuthParameters(USER_NAME, PASSWORD))
        .build();

    try {
        InitiateAuthResponse authResult = cognitoClient.initiateAuth(authRequest);

        if (authResult.challengeName() != null) {
            if (authResult.challengeName().equals(ChallengeNameType.NEW_PASSWORD_REQUIRED.toString())) {
                try {
                    reimpostaPassword.apriSchermataReimpostaPassword(event);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            } else {
                // 认证成功
                AuthenticationResultType authenticationResult = authResult.authenticationResult();
                System.out.println("Access token: " + authenticationResult.accessToken());
            }
        }
    } catch (NotAuthorizedException e) {
        System.out.println("用户名或密码不正确");
    } catch (PasswordResetRequiredException e) {
        System.out.println("用户需要重置密码");
    }
}

当我使用正确的用户名和密码填写我的表单时,它会给我一个错误:

Caused by: java.lang.NullPointerException: 无法调用software.amazon.awssdk.services.cognitoidentityprovider.model.AuthenticationResultType.accessToken()”,因为authenticationResult为空
	at com.example.ratatouille23/com.example.ratatouille23.Login.LoginController.Login(LoginController.java:101)
	at com.example.ratatouille23/com.example.ratatouille23.Login.LoginController.clickPulsanteLogin(LoginController.java:66)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
... 51 more

导致错误的代码行是:

System.out.println("Access token: " + authenticationResult.accessToken());

这是一种奇怪的行为,因为这意味着“如果挑战是新密码所需的”控制失败了,所以我有点困惑。

有什么帮助吗?

英文:

i'm developing for the first time using AWS Cognito in Java.

I created a code for an Admin to create a User. The user will be automatically created with the status FORCE_CHANGE_PASSWORD. What i was going to do now is a simple login, but if the system return a CHANGE_PASSWORD challenge, then it will open another window where the user should input old password and new password, then submit them to cognito.

The code i used to create a user through AdminCreateUser is the following:

 // Creating instance of client CognitoIdentityProvider
CognitoIdentityProviderClient cognitoClient = CognitoIdentityProviderClient.builder().region(Region.EU_CENTRAL_1).build();
AdminCreateUserRequest requestUserCreation = AdminCreateUserRequest.builder()
.username(usernameTextField.getText())
.desiredDeliveryMediums(DeliveryMediumType.EMAIL)
.userAttributes(AttributeType.builder()
.name("email")
.value(emailTextField.getText())
.build())
.userPoolId("xxxxx")
.build();
// Sending sign up request
AdminCreateUserResponse responseUserCreation = cognitoClient.adminCreateUser(requestUserCreation);
// Saving the group we want to put the user in through a combobox
String groupname = (String) groupComboBox.getValue();
UserType newUser = responseUserCreation.user();
GroupType group = GroupType.builder().groupName(groupname).build();
AdminAddUserToGroupRequest addUserToGroupRequest = AdminAddUserToGroupRequest.builder()
.userPoolId("xxxxx")
.username(newUser.username())
.groupName(groupname)
.build();
AdminAddUserToGroupResponse addUserToGroupResult = cognitoClient.adminAddUserToGroup(addUserToGroupRequest);

This code works. When i submit this through a button, an email arrives to the user i created, and it also shows in my Amazon Cognito console.

Now the login part is giving me trouble.

As i said, i want to open another windows which has the right form for resetting the password. I still haven't thought about the implementation for resetting the password because my login doesnt' work, so i will implement this later.

This is my login code:

public void Login(ActionEvent event) {
final String CLIENT_ID = cs.getAppClientId();
final String USER_NAME = userNameTextField.getText();
final String PASSWORD = passwordTextField.getText();
final Region region = cs.getRegion();
CognitoIdentityProviderClient cognitoClient = CognitoIdentityProviderClient.builder()
.credentialsProvider(DefaultCredentialsProvider.create())
.region(region)
.build();
InitiateAuthRequest authRequest = InitiateAuthRequest.builder()
.clientId(CLIENT_ID)
.authFlow("USER_PASSWORD_AUTH")
.authParameters(createAuthParameters(USER_NAME, PASSWORD))
.build();
try {
InitiateAuthResponse authResult = cognitoClient.initiateAuth(authRequest);
if (authResult.challengeName() != null) {
if (authResult.challengeName().equals(ChallengeNameType.NEW_PASSWORD_REQUIRED.toString())) {
try {
reimpostaPassword.apriSchermataReimpostaPassword(event);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
// The authentication was successful
AuthenticationResultType authenticationResult = authResult.authenticationResult();
System.out.println("Access token: " + authenticationResult.accessToken());
}
}
} catch (NotAuthorizedException e) {
System.out.println("Incorrect username or password");
} catch (PasswordResetRequiredException e) {
System.out.println("Password reset is required for the user");
}

When i fill my form with the right username and password, it gives me this error:

Caused by: java.lang.NullPointerException: Cannot invoke "software.amazon.awssdk.services.cognitoidentityprovider.model.AuthenticationResultType.accessToken()" because "authenticationResult" is null
at com.example.ratatouille23/com.example.ratatouille23.Login.LoginController.Login(LoginController.java:101)
at com.example.ratatouille23/com.example.ratatouille23.Login.LoginController.clickPulsanteLogin(LoginController.java:66)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
... 51 more

The line that gives me error is this:

System.out.println("Access token: " + authenticationResult.accessToken());

This is an odd behaviour, because this means that the 'if the challenge is new password required' control fails, so i'm a little stuck here.

Any help?

答案1

得分: 2

我正在处理这个用例。为了使一个非常相似的示例运行起来,我创建了一个用户池,其中包含一个允许我使用这些身份验证流程的应用程序。

当我执行使用 identityProviderClient.adminInitiateAuth() 的 AWS SDK for Java V2 代码时,我成功获取了一个访问令牌,如下所示。

当我提供了一个不正确的密码时,我会得到一个预期的异常。

以下是一个Java代码示例。要运行这个Java代码示例,需要在指定的用户池中创建一个新用户,并使用临时密码。您将在响应中获得一个挑战类型值为 NEW_PASSWORD_REQUIRED。

您不能读取访问令牌。然后,该代码将临时密码更改为永久密码。现在用户可以使用永久密码登录,然后您可以读取访问令牌。

public class GetAccessToken {

    public static void main(String[]args) {
        final String usage = "\n" +
            "Usage:\n" +
            "    <clientId> <poolId> <username> <tempPassword> <permanentPassword>\n\n" +
            "Where:\n" +
            "    clientId - 您可以从AWS CDK脚本中获取的应用客户端ID值。\n\n" +
            "    poolId - 具有用户的池ID。\n\n" +
            "    username - 具有临时密码的新用户名。\n\n" +
            "    tempPassword - 临时密码。\n\n" +
            "    permanentPassword - 永久密码。\n\n" ;

        if (args.length != 5) {
            System.out.println(usage);
            System.exit(1);
        }
        
        String clientId = args[0];
        String poolId = args[1];
        String username = args[2];
        String tempPassword = args[3];
        String permanentPassword = args[4];

        CognitoIdentityProviderClient identityProviderClient = CognitoIdentityProviderClient.builder()
            .region(Region.US_EAST_1)
            .credentialsProvider(ProfileCredentialsProvider.create())
            .build();

        boolean wasLoggedIn = getToken(identityProviderClient, clientId, username, tempPassword, poolId);
        if (wasLoggedIn)
            System.out.println(username + " successfully authenticated");
        else {
            // 将临时密码更改为永久密码,然后再次调用getToken()。现在您将获得访问令牌。
            changeTempPassword(identityProviderClient, username, permanentPassword, poolId);
            getToken(identityProviderClient, clientId, username, permanentPassword, poolId);
            System.out.println(username + " successfully authenticated");
        }
    }

    public static boolean getToken(CognitoIdentityProviderClient identityProviderClient, String clientId, String username, String password, String poolId) {
        final Map<String, String> authParams = new HashMap<>();
        authParams.put("USERNAME", username);
        authParams.put("PASSWORD", password);

        AdminInitiateAuthRequest authRequest = AdminInitiateAuthRequest.builder()
            .clientId(clientId)
            .userPoolId(poolId)
            .authParameters(authParams)
            .authFlow(AuthFlowType.ADMIN_USER_PASSWORD_AUTH)
            .build();

        try {
            // 如果您提供了不正确的用户名/密码,将抛出异常。
            AdminInitiateAuthResponse response = identityProviderClient.adminInitiateAuth(authRequest);

            // 获取挑战类型
            if (response.challengeNameAsString() == null) {
                System.out.println("访问令牌类型: " + response.authenticationResult().tokenType());
                System.out.println("访问令牌: " + response.authenticationResult().accessToken());
                return true;
            } else if (response.challengeNameAsString().compareTo("NEW_PASSWORD_REQUIRED") == 0) {
                System.out.println("用户必须更改他们的密码。");
            }

        } catch(CognitoIdentityProviderException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
        return false;
    }

    public static void changeTempPassword(CognitoIdentityProviderClient identityProviderClient, String username, String newPassword, String poolId){
        try {
            AdminSetUserPasswordRequest passwordRequest = AdminSetUserPasswordRequest.builder()
                .username(username)
                .userPoolId(poolId)
                .password(newPassword)
                .permanent(true)
                .build();

            identityProviderClient.adminSetUserPassword(passwordRequest);
            System.println("密码成功更改");

        } catch(CognitoIdentityProviderException e) {
            System.err.println(e.awsErrorDetails().errorMessage());
            System.exit(1);
        }
    }
}

因此,您获得此NULL异常的原因是因为您需要为用户设置永久密码。如果challengeName=NEW_PASSWORD_REQUIRED,您无法读取访问令牌。

英文:

I am working on this use case now. To get a very similiar example working, I created a user pool with an App that lets me use these Authentication flows.

AWS Cognito,为什么InitiateAuthResponse为null?

When I execute my AWS SDK for Java V2 code that uses identityProviderClient.adminInitiateAuth() - I successfully get an Access Token - as shown here.

AWS Cognito,为什么InitiateAuthResponse为null?

WHen i speicfy an incorrect password, I get exception as expected.

Here is a Java code example. To run this Java code example, create a new user in the specified user pool with a temporary password. You will get back a challenge type value of NEW_PASSWORD_REQUIRED in the response.

You cannot read the access token. This code then changes the temporary password to a permanent password. Now the user can log in with the permanent password and you can read the access token.

public class GetAccessToken {
public static void main(String[]args) {
final String usage = &quot;\n&quot; +
&quot;Usage:\n&quot; +
&quot;    &lt;clientId&gt; &lt;poolId&gt; &lt;username&gt; &lt;tempPassword&gt; &lt;permanentPassword&gt;\n\n&quot; +
&quot;Where:\n&quot; +
&quot;    clientId - The app client Id value that you can get from the AWS CDK script.\n\n&quot; +
&quot;    poolId - The pool Id that has the user. \n\n&quot; +
&quot;    username - The new user name with a temp password. \n\n&quot; +
&quot;    tempPassword - The temp password. \n\n&quot; +
&quot;    permanentPassword - The permanent password. \n\n&quot; ;
if (args.length != 5) {
System.out.println(usage);
System.exit(1);
}
String clientId = args[0];
String poolId = args[1];
String username = args[2];
String tempPassword = args[3];
String permanentPassword = args[4];
CognitoIdentityProviderClient identityProviderClient = CognitoIdentityProviderClient.builder()
.region(Region.US_EAST_1)
.credentialsProvider(ProfileCredentialsProvider.create())
.build();
boolean wasLoggedIn = getToken(identityProviderClient, clientId, username, tempPassword, poolId);
if (wasLoggedIn)
System.out.println(username +&quot; successfully authenticated&quot;);
else {
// Change the temp password to a permanent one and then call getToken() again. Now you will
// get access tokens.
changeTempPassword(identityProviderClient, username, permanentPassword, poolId);
getToken(identityProviderClient, clientId, username, permanentPassword, poolId);
System.out.println(username +&quot; successfully authenticated&quot;);
}
}
public static boolean getToken(CognitoIdentityProviderClient identityProviderClient, String clientId, String username, String password, String poolId) {
final Map&lt;String, String&gt; authParams = new HashMap&lt;&gt;();
authParams.put(&quot;USERNAME&quot;, username);
authParams.put(&quot;PASSWORD&quot;, password);
AdminInitiateAuthRequest authRequest = AdminInitiateAuthRequest.builder()
.clientId(clientId)
.userPoolId(poolId)
.authParameters(authParams)
.authFlow(AuthFlowType.ADMIN_USER_PASSWORD_AUTH)
.build();
try {
// If you specify an incorrect username/password, an exception is thrown.
AdminInitiateAuthResponse response = identityProviderClient.adminInitiateAuth(authRequest);
// Get the Challenge type
if (response.challengeNameAsString() == null) {
System.out.println(&quot;Access Token Type : &quot; + response.authenticationResult().tokenType());
System.out.println(&quot;Access Token : &quot; + response.authenticationResult().accessToken());
return true;
} else if (response.challengeNameAsString().compareTo(&quot;NEW_PASSWORD_REQUIRED&quot;) == 0) {
System.out.println(&quot;The User must change their password. &quot;);
}
} catch(CognitoIdentityProviderException e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
return false;
}
public static void changeTempPassword(CognitoIdentityProviderClient identityProviderClient, String username, String newPassword, String poolId){
try {
AdminSetUserPasswordRequest passwordRequest = AdminSetUserPasswordRequest.builder()
.username(username)
.userPoolId(poolId)
.password(newPassword)
.permanent(true)
.build();
identityProviderClient.adminSetUserPassword(passwordRequest);
System.out.println(&quot;The password was successfully changed&quot;);
} catch(CognitoIdentityProviderException e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
}
}

SO the reason why you get this NULL Exception is because you need to set the permanent password for the user. If the challengeName=NEW_PASSWORD_REQUIRED, you cannot read the access token.

huangapple
  • 本文由 发表于 2023年2月17日 23:57:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/75486547.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定