AWS Cognito自定义无密码流集成SOFTWARE_TOKEN_MFA遇CodeMismatch错误
问题诊断与解决方案
核心问题
你的DefineAuthChallenge函数中第一个条件判断逻辑错误,导致系统在处理SOFTWARE_TOKEN_MFA挑战时直接拒绝认证。
原代码中第一个条件:
if (event.request.session && event.request.session.find(attempt => attempt.challengeName !== 'CUSTOM_CHALLENGE')) { event.response.issueTokens = false; event.response.failAuthentication = true; }
这个逻辑会拒绝所有包含非CUSTOM_CHALLENGE的会话,包括你在CUSTOM_CHALLENGE成功后切换的SOFTWARE_TOKEN_MFA挑战。当用户提交MFA验证码时,会话中会同时存在成功的CUSTOM_CHALLENGE记录和当前的SOFTWARE_TOKEN_MFA尝试记录,此时find方法会找到非CUSTOM_CHALLENGE的条目,直接触发认证失败,从而抛出CodeMismatchException(实际是认证状态被提前拒绝,而非验证码错误)。
修复方案
修改第一个条件的逻辑,仅在用户未通过CUSTOM_CHALLENGE前拒绝非CUSTOM_CHALLENGE的挑战,允许通过自定义挑战后的SOFTWARE_TOKEN_MFA验证流程:
/** * @type {import('@types/aws-lambda').DefineAuthChallengeTriggerHandler} */ const getUserPreferredMFA = require('./functions/getUserPreferredMFA'); //define-challenge exports.handler = async event => { try { console.log("event: ", JSON.stringify(event, null, 2)); } catch (err) { console.log("error: ", err); } // 判断用户是否已通过CUSTOM_CHALLENGE const hasPassedCustomChallenge = event.request.session?.some(attempt => attempt.challengeName === 'CUSTOM_CHALLENGE' && attempt.challengeResult === true ); // 仅在未通过自定义挑战时,拒绝非CUSTOM_CHALLENGE的请求 if (!hasPassedCustomChallenge && event.request.session && event.request.session.find(attempt => attempt.challengeName !== 'CUSTOM_CHALLENGE')) { event.response.issueTokens = false; event.response.failAuthentication = true; } else if (event.request.session && event.request.session.length >= 3 && event.request.session.slice(-1)[0].challengeResult === false) { // 连续3次错误尝试,拒绝认证 event.response.issueTokens = false; event.response.failAuthentication = true; } else if (event.request.session && event.request.session.length && event.request.session.slice(-1)[0].challengeName === 'CUSTOM_CHALLENGE' && event.request.session.slice(-1)[0].challengeResult === true) { if (await getUserPreferredMFA(event.userPoolId, event.userName) === "SOFTWARE_TOKEN_MFA") { event.response.challengeName = 'SOFTWARE_TOKEN_MFA'; event.response.issueTokens = false; event.response.failAuthentication = false; } else { event.response.issueTokens = true; event.response.failAuthentication = false; } } else if (event.request.session && event.request.session.slice(-1)[0].challengeName === 'SOFTWARE_TOKEN_MFA' && event.request.session.slice(-1)[0].challengeResult === true) { // 处理SOFTWARE_TOKEN_MFA验证成功的情况,颁发令牌 event.response.issueTokens = true; event.response.failAuthentication = false; } else { // 初始或未完成自定义挑战,继续CUSTOM_CHALLENGE event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = 'CUSTOM_CHALLENGE'; } return event; };
关键修改说明
- 新增
hasPassedCustomChallenge判断:标记用户是否已成功完成自定义邮箱验证码挑战,避免后续的MFA挑战被误判为非法请求。 - 调整第一个条件的触发逻辑:仅在未通过自定义挑战时,才拒绝非
CUSTOM_CHALLENGE的请求。 - 新增
SOFTWARE_TOKEN_MFA成功后的处理分支:当MFA验证码验证通过时,直接颁发认证令牌,完成登录流程。
验证流程
修改后,认证流程将正常执行:
- 用户输入邮箱调用
Auth.signIn,返回CUSTOM_CHALLENGE; - 提交邮箱验证码,
CUSTOM_CHALLENGE验证通过; - 系统检测到用户启用了
SOFTWARE_TOKEN_MFA,切换至该挑战; - 用户提交MFA验证码,
SOFTWARE_TOKEN_MFA验证通过,系统颁发令牌,登录完成。
内容的提问来源于stack exchange,提问作者Abiram
相关产品推荐
相关产品推荐

