Go语言 AWS Cognito的SMS多因素身份验证返回无效代码或身份验证状态

ffvjumwh  于 2024-01-04  发布在  Go
关注(0)|答案(2)|浏览(168)

我正在尝试使用他们的Go SDK实现构建在Cognito上的身份验证。我已经能够让基本的username/password身份验证工作,但是当我使用SMS添加双因素身份验证时,我就卡住了。
重现步骤:
1.我使用用户名/密码和电子邮件验证创建用户
1.我验证电子邮件地址
1.我设置了电话号码并请求验证码
1.我核实了电话号码
1.我启用了双重身份验证(通过短信)
1.我尝试登录并接收SMS_MFA挑战
1.我在手机上收到该代码,并呼叫AdminRespondToAuthChallenge
问题,我收到一个error

  1. CodeMismatchException: Invalid code or auth state for the user.
  2. status code: 400, request id: 1513894e-8efa-11e8-a8f8-97e5e083c03b

字符串
短信验证码肯定是正确的,所以看起来一定是和auth状态有关。
对Cognito的调用如下所示:

  1. c.cip.SignUp(&cognitoidentityprovider.SignUpInput{
  2. ClientId: aws.String(c.clientID),
  3. Username: aws.String(username),
  4. Password: aws.String(password),
  5. UserAttributes: []*cognitoidentityprovider.AttributeType{
  6. {
  7. Name: aws.String("email"),
  8. Value: aws.String(email),
  9. },
  10. {
  11. Name: aws.String("name"),
  12. Value: aws.String(fullName),
  13. },
  14. },
  15. })
  16. c.cip.ConfirmSignUp(&cognitoidentityprovider.ConfirmSignUpInput{
  17. ClientId: aws.String(c.clientID),
  18. Username: aws.String(username),
  19. ConfirmationCode: aws.String(code),
  20. })
  21. //Add the phone number
  22. c.cip.AdminUpdateUserAttributes(&cognitoidentityprovider.AdminUpdateUserAttributesInput{
  23. UserPoolId: aws.String(c.userPoolID),
  24. Username: aws.String(username),
  25. UserAttributes: []*cognitoidentityprovider.AttributeType{
  26. {
  27. Name: aws.String("phone_number"),
  28. Value: aws.String(phoneNumber),
  29. },
  30. },
  31. })
  32. //Request a verification code
  33. c.cip.GetUserAttributeVerificationCode(&cognitoidentityprovider.GetUserAttributeVerificationCodeInput{
  34. AccessToken: aws.String(accessToken),
  35. AttributeName: aws.String("phone_number"),
  36. })
  37. //Verify the phone number
  38. c.cip.VerifyUserAttribute(&cognitoidentityprovider.VerifyUserAttributeInput{
  39. AccessToken: aws.String(accessToken),
  40. AttributeName: aws.String("phone_number"),
  41. Code: aws.String(code),
  42. })
  43. //Enable SMS 2-factor auth c.cip.AdminSetUserSettings(&cognitoidentityprovider.AdminSetUserSettingsInput{
  44. UserPoolId: aws.String(c.userPoolID),
  45. Username: aws.String(username),
  46. MFAOptions: []*cognitoidentityprovider.MFAOptionType{
  47. &cognitoidentityprovider.MFAOptionType{
  48. AttributeName: aws.String("phone_number"),
  49. DeliveryMedium: aws.String("SMS"),
  50. },
  51. },
  52. })
  53. c.cip.AdminInitiateAuth(&cognitoidentityprovider.AdminInitiateAuthInput{
  54. ClientId: aws.String(c.clientID),
  55. UserPoolId: aws.String(c.userPoolID),
  56. AuthFlow: aws.String("ADMIN_NO_SRP_AUTH"),
  57. AuthParameters: map[string]*string{
  58. "USERNAME": aws.String(username),
  59. "PASSWORD": aws.String(password),
  60. },
  61. })
  62. c.cip.AdminRespondToAuthChallenge(&cognitoidentityprovider.AdminRespondToAuthChallengeInput{
  63. ClientId: aws.String(c.clientID),
  64. UserPoolId: aws.String(c.userPoolID),
  65. ChallengeName: aws.String("SMS_MFA"),
  66. Session: aws.String(session),
  67. ChallengeResponses: map[string]*string{
  68. "USERNAME": aws.String(username),
  69. "SMS_MFA_CODE": aws.String(code),
  70. },
  71. })


执行GetUser调用将显示用户的当前状态:

  1. User = {
  2. Enabled: true,
  3. MFAOptions: [{
  4. AttributeName: "phone_number",
  5. DeliveryMedium: "SMS"
  6. }],
  7. PreferredMfaSetting: "SMS_MFA",
  8. UserAttributes: [
  9. {
  10. Name: "sub",
  11. Value: "bd2bb8bc-dfe6-4216-829c-5ae975ce24e5"
  12. },
  13. {
  14. Name: "email_verified",
  15. Value: "true"
  16. },
  17. {
  18. Name: "name",
  19. Value: "Ben Vogan"
  20. },
  21. {
  22. Name: "phone_number_verified",
  23. Value: "true"
  24. },
  25. {
  26. Name: "phone_number",
  27. Value: "<redacted>"
  28. },
  29. {
  30. Name: "email",
  31. Value: "<redacted>"
  32. }
  33. ],
  34. UserCreateDate: 2018-07-24 03:29:49 +0000 UTC,
  35. UserLastModifiedDate: 2018-07-24 04:19:51 +0000 UTC,
  36. UserMFASettingList: ["SMS_MFA"],
  37. UserStatus: "CONFIRMED",
  38. Username: "bd2bb8bc-dfe6-4216-829c-5ae975ce24e5"
  39. }


我不知道是否有办法查询用户的身份验证状态,以便我可以验证。
AWS文档和无用的错误让我抓狂,所以任何帮助都将不胜感激!
谢谢.

mm5n2pyu

mm5n2pyu1#

你的问题似乎模棱两可。
第二步你是
1.我设置了电话号码并请求验证码
1.我核实了电话号码
如果你已经正确配置了这个池,这就是Cognito中的MFA。
你不能既有手机登录和MFA。这没有意义。
但如果你有手机登录,那么Cognito将发送短信每次与代码。密码是只用于电子邮件登录。

rqcrx0a6

rqcrx0a62#

经过大量的挖掘和浏览amplify/cognito js repos中的开放问题,我找到了这个解决方案。
在接收到作为SMS的代码后,不要再次触发/调用身份验证流程以发送SMS MFA代码,这会导致代码无效,并且在收到错误后,您可能会注意到另一个SMS MFA代码正在发送,这是由于最后一次身份验证调用发送初始SMS MFA代码。
相反,创建另一个路径或方法,您可以在其中使用adminRespondToAuthChallengesendMFACode,前提是Session参数必须具有上次authenticate调用的session值。
我使用的是JS包而不是Go,但逻辑必须相同。在我的例子中,我构建了REST API,它在Lambda中调用authenticate函数。
authenticate函数在用户提交邮箱和密码后被调用。

  1. import { CognitoUser } from 'amazon-cognito-identity-js';
  2. // inside authenticate lambda function
  3. const userData = {
  4. Username: user.email,
  5. Pool: userPool
  6. };
  7. const cognitoUser = new CognitoUser(userData);
  8. cognitoUser.authenticateUser(authenticationDetails, {
  9. onSuccess: ...,
  10. onFailure: ...,
  11. mfaRequired: (challengeName, challengeParameters) => {
  12. const { Session } = cognitoUser;
  13. if (payload.mfa === undefined) {
  14. // returns mfaRequired response to frontend
  15. resolve({mfaRequired: true, session: Session})
  16. }
  17. }
  18. })

字符串
sendSMSMFA Lambda函数,用户在前端输入代码后调用

  1. // inside sendSMSMFA function
  2. const cognitoAdminUser = new CognitoIdentityServiceProvider({apiVersion: '2016-04-18'});
  3. cognitoAdminUser.adminRespondToAuthChallenge({
  4. UserPoolId: user_pool_id,
  5. ClientId: client_id,
  6. ChallengeName: 'SMS_MFA',
  7. Session: payload.session,
  8. ChallengeResponses: {
  9. SMS_MFA_CODE: payload.mfaCode,
  10. USERNAME: payload.email
  11. },
  12. }, (err, data) => {
  13. if (err) {
  14. console.log('error responding to auth challenge', err);
  15. reject(err);
  16. } else {
  17. console.log('Successfully responded to auth challenge', data);
  18. const idToken = data.AuthenticationResult.IdToken;
  19. const AccessToken = data.AuthenticationResult.AccessToken;
  20. const refreshToken = data.AuthenticationResult.RefreshToken;
  21. resolve({token: idToken, access: AccessToken, refresh: refreshToken})
  22. }
  23. })


在开放问题的某个地方,我读到了一个功能请求,它专门要求一个验证SMS MFA代码并返回令牌的函数,但在此之前,我认为这是一个笨拙的方法。
对于任何人谁想知道为什么这是不发生时,使用TOTP软件令牌方法是因为MFA代码时钟是独立的认知时钟,因此将始终有一个同步,即使代码发送在不同的authenticate调用,但短信MFA是真正依赖于会话ID.

展开查看全部

相关问题