AWS Cognito:带重试的自定义挑战

问题描述 投票:0回答:2

我正在使用 MFA 自定义挑战,因为我想使用 Twilio 而不是 AMAZON SNS。我已经成功实施了它。它工作正常但是 当用户输入错误的 OTP 代码时。用户会话已过期。意味着他必须再次提供电话号码并再次请求 OTP。而我希望它至少重试 3 次。在他需要请求另一个 OTP 之前。 我的响应验证触发器如下所示,有什么我们可以做的吗?

(event, context, callback) => {
    if (event.request.privateChallengeParameters.answer == event.request.challengeAnswer) {
        event.response.answerCorrect = true;
    } else {
        event.response.answerCorrect = false;
    }
    callback(null, event);
}
amazon-web-services aws-lambda amazon-cognito
2个回答
12
投票

我通过将答案作为变量添加到challengeMetaData中来实现这一点 - 据我所知,它不会返回给客户端,但可以在后续调用中使用,我还有一个名为 attempts 的变量来跟踪用户输入的次数一个不正确的值。我的代码如下 - 我希望它有帮助

const AWS = require("aws-sdk");
exports.handler = (event, context, callback) => {

    const session = event.request.session;
    const currentSession = session ? session.length - 1 : 0

    switch (event.triggerSource) {
        case 'DefineAuthChallenge_Authentication':

            console.log("DefineAuthChallenge_Authentication");
            console.log(event);

            if (session.length === 0) {
                event.response = {
                    challengeName: 'CUSTOM_CHALLENGE',
                    failAuthentication: false,
                    issueTokens: false
                };
            }
            else {
                if (session[currentSession].challengeName === 'CUSTOM_CHALLENGE') {

                    if (session[currentSession].challengeResult === true) {
                        event.response.issueTokens = true;
                        event.response.failAuthentication = false;
                    }
                    else {

                        let metaData = JSON.parse(session[currentSession].challengeMetadata);
                        if (metaData.attempts <= 3) {
                            event.response = {
                                challengeName: 'CUSTOM_CHALLENGE',
                                failAuthentication: false,
                                issueTokens: false
                            };
                        }
                        else {
                            event.response.issueTokens = false;
                            event.response.failAuthentication = true;
                        }
                    }
                }
            }
            console.log(event);
            break;
        case 'CreateAuthChallenge_Authentication':
            if (event.request.challengeName === 'CUSTOM_CHALLENGE') {
                console.log("CreateAuthChallenge_Authentication");
                console.log(event);
                if (session.length === 0) {
                    let answer = Math.random().toString(10).substr(2, 6);

//Your logic to send a message goes here
                    
                    event.response.publicChallengeParameters = { challengeType: 'SMS_CODE' };
                    event.response.privateChallengeParameters = { answer: answer };
                    event.response.challengeMetadata = JSON.stringify({ '_sid': answer, 'challengeType': 'SMS_CODE', attempts: 1 });
                }
                else {
                    let metaData = JSON.parse(session[currentSession].challengeMetadata);
                    if (metaData.attempts <= 3) {
                        event.response.publicChallengeParameters = { challengeType: 'SMS_CODE', errorCode: 'NotAuthorizedException' };
                        event.response.privateChallengeParameters = { answer: metaData._sid };
                        event.response.challengeMetadata = JSON.stringify({ '_sid': metaData._sid, 'challengeType': 'SMS_CODE', attempts: metaData.attempts + 1 });
                    }
                }
            }
            console.log(event);
            break;
        default:
            console.log("VerifyAuthChallenge_Authentication");
            console.log(event);
            if (event.request.privateChallengeParameters.answer === event.request.challengeAnswer) {
                event.response.answerCorrect = true;
            }
            else { event.response.answerCorrect = false; }
            console.log(event);
            break;
    }
    callback(null, event);
};


0
投票

对于使用 CognitoIdentityProviderClient(@aws-sdk/client-cognito-identity-provider) 的任何人。

发出无效的 otp/answer 后将创建新会话。 第二次尝试应使用新会话,否则身份验证将失败。

async verifyOTP({ username, otp, session }) {
const input: RespondToAuthChallengeCommandInput = {
  ClientId: process.env.COGNITO_CLIENT_ID,
  ChallengeName: ChallengeNameType.CUSTOM_CHALLENGE,
  Session: session,
  ChallengeResponses: {
    ANSWER:  otp,
    USERNAME: username,
  },
};
try {
  const command = new RespondToAuthChallengeCommand(input);
  const response = await this.client.send(command);
  // sent to client after failed attempt
  if (!response.AuthenticationResult) {
    const { Session, ChallengeParameters } = response;
    return {
      Session,
      attempts: ChallengeParameters.attempts,
      attemptsLeft: ChallengeParameters.attemptsLeft,
    };
  }
  return response.AuthenticationResult;
} catch (error) {
  throw new ForbiddenException("Incorrect  OTP");
}

}

在客户端需要检索新会话并使用新会话调用验证 otp,即 verifyOTP({username:'test', otp:'1234', session: newSession})。

另请参阅此处的 cognito lambda 触发器:cognito lambda 触发器要点

© www.soinside.com 2019 - 2024. All rights reserved.