英文:
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.
When I execute my AWS SDK for Java V2 code that uses identityProviderClient.adminInitiateAuth() - I successfully get an Access Token - as shown here.
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 = "\n" +
"Usage:\n" +
" <clientId> <poolId> <username> <tempPassword> <permanentPassword>\n\n" +
"Where:\n" +
" clientId - The app client Id value that you can get from the AWS CDK script.\n\n" +
" poolId - The pool Id that has the user. \n\n" +
" username - The new user name with a temp password. \n\n" +
" tempPassword - The temp password. \n\n" +
" permanentPassword - The permanent password. \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 {
// 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 +" 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 {
// 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("Access Token Type : " + response.authenticationResult().tokenType());
System.out.println("Access Token : " + response.authenticationResult().accessToken());
return true;
} else if (response.challengeNameAsString().compareTo("NEW_PASSWORD_REQUIRED") == 0) {
System.out.println("The User must change their password. ");
}
} 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("The password was successfully changed");
} 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论