如何在AWS Cognito身份验证流程中包括TOTP MFA

时间:2020-01-15 17:30:06

标签: amazon-cognito multi-factor-authentication totp

我正在使用Cognito用户池来验证我的Web应用程序。我现在一切正常,但是现在我需要为其启用MFA。我现在就是这样做的(提供的所有代码都是服务器端代码):

  1. 注册用户:
const cognito = new AWS.CognitoIdentityServiceProvider();
cognito.signUp({
    ClientId,
    Username: email,
    Password,
}).promise();
  1. 带有内部代码的电子邮件将发送到用户的地址(在上一个函数调用中称为用户名)。

  2. 用户读取代码并将代码提供给下一个函数调用:

cognito.confirmSignUp({
    ClientId,
    ConfirmationCode,
    Username: email,
    ForceAliasCreation: false,
}).promise();
  1. 用户登录:
const tokens = await cognito.adminInitiateAuth({
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    ClientId,
    UserPoolId,
    AuthParameters: {
        'USERNAME': email,
        'PASSWORD': password,
    },
}).promise();

我对此过程非常满意。但是现在我需要为此添加TOTP MFA功能。有人可以告诉我如何更改这些步骤吗?顺便说一句,我知道创建用户池时需要为用户池启用TOTP MFA。我只是在问它如何影响我的注册/登录过程。

1 个答案:

答案 0 :(得分:5)

好的,我自己找到了一种方法。我必须说,我找不到关于此的任何文档,因此,使用后果自负!

当然,此过程假设您有一个启用了MFA的用户池(我使用了TOTP MFA)。

  1. 注册用户:
const cognito = new AWS.CognitoIdentityServiceProvider();
cognito.signUp({
    ClientId,
    Username: email,
    Password,
}).promise();
  1. 带有内部代码的电子邮件将发送到用户的地址(在上一个函数调用中称为用户名)。

  2. 用户读取代码并将代码提供给下一个函数调用:

cognito.confirmSignUp({
    ClientId,
    ConfirmationCode: code,
    Username: email,
    ForceAliasCreation: false,
}).promise();
  1. 第一次登录:
await cognito.adminInitiateAuth({
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    ClientId,
    UserPoolId,
    AuthParameters: {
        'USERNAME': email,
        'PASSWORD': password,
    },
}).promise();

这时,返回值将有所不同(与未执行MFA时得到的返回值相比)。返回值将类似于:

{
  "ChallengeName": "MFA_SETUP",
  "Session": "...",
  "ChallengeParameters": {
    "MFAS_CAN_SETUP": "[\"SOFTWARE_TOKEN_MFA\"]",
    "USER_ID_FOR_SRP": "..."
  }
}

返回的对象是说用户需要登录MFA_SETUP才能登录(每次用户注册一次)。

  1. 为用户启用TOTP MFA:
cognito.associateSoftwareToken({
  Session,
}).promise();

需要上一个呼叫,因为有两个选项,并且通过发出给定的呼叫,您告诉Cognito您希望用户启用TOTP MFA(而不是SMS MFA)。 Session输入是上一个函数调用返回的一个。现在,这一次它将返回此值:

{
  "SecretCode": "...",
  "Session": "..."
}
  1. 用户必须使用给定的SecretCode并将其输入“ Google Authenticator”之类的应用中。添加后,该应用将开始显示6位数字,该数字每分钟刷新一次。

  2. 验证身份验证器应用程序:

cognito.verifySoftwareToken({
  UserCode: '123456',
  Session,
}).promise()

Session输入将是步骤5中返回的字符串,UserCode是当前在身份验证器应用程序上显示的6位数字。如果成功完成此操作,则将获得以下返回值:

{
  "Status": "SUCCESS",
  "Session": "..."
}

我没有发现此对象返回的会话有任何用处。现在,注册过程已完成,用户可以登录。

  1. 实际登录(每次用户想要进行身份验证时都会发生):
await cognito.adminInitiateAuth({
    AuthFlow: 'ADMIN_NO_SRP_AUTH',
    ClientId,
    UserPoolId,
    AuthParameters: {
        'USERNAME': email,
        'PASSWORD': password,
    },
}).promise();

当然,这与步骤4相同。但是其返回值不同:

{
  "ChallengeName": "SOFTWARE_TOKEN_MFA",
  "Session": "...",
  "ChallengeParameters": {
    "USER_ID_FOR_SRP": "..."
  }
}

这是告诉您要完成登录过程,您需要遵循SOFTWARE_TOKEN_MFA挑战过程。

  1. 通过提供MFA来完成登录过程:
cognito.adminRespondToAuthChallenge({
  ChallengeName: "SOFTWARE_TOKEN_MFA",
  ClientId,
  UserPoolId,
  ChallengeResponses: {
    "USERNAME": config.username,
    "SOFTWARE_TOKEN_MFA_CODE": mfa,
  },
  Session,
}).promise()

Session输入是第8步返回的数字,mfa是需要从身份验证器应用读取的6位数字。调用该函数后,它将返回令牌:

{
  "ChallengeParameters": {},
  "AuthenticationResult": {
    "AccessToken": "...",
    "ExpiresIn": 3600,
    "TokenType": "Bearer",
    "RefreshToken": "...",
    "IdToken": "..."
  }
}
相关问题