Cognito自定义认证流调用respondToAuthChallenge报‘Invalid session for the user’错误排查求助
我帮你排查了下这个Invalid session for the user的问题,大概率是几个细节没处理对,咱们一步步来解决:
1. 移除AdminInitiateAuth中多余的CHALLENGE_NAME参数
当使用AuthFlowType.CUSTOM_AUTH发起初始认证请求时,不需要在authParams里添加CHALLENGE_NAME参数——这个参数是在响应挑战阶段才会用到的。多余的参数会干扰Cognito生成有效会话,导致后续响应挑战时session验证失败。
修改后的认证流程初始化代码:
try { AWSCognitoIdentityProvider client = getAWSCognitoIdentityClient(); String username = "testuser"; String password = "password1"; final Map<String, String> authParams = new HashMap<String, String>(); authParams.put("USERNAME", username); authParams.put("PASSWORD", password); // 移除多余的CHALLENGE_NAME参数 final AdminInitiateAuthRequest initiateAuthRequest = new AdminInitiateAuthRequest() .withClientId("my client id") .withUserPoolId("my user pool") .withAuthFlow(AuthFlowType.CUSTOM_AUTH) .withAuthParameters(authParams); final AdminInitiateAuthResult result = client.adminInitiateAuth(initiateAuthRequest); String mfaCode = getUserInput(); authenticateMFA(result, mfaCode); } catch (Exception e) { e.printStackTrace(); }
2. 修正Create Challenge Lambda中challengeMetadata的使用
你现在把验证码直接存在了challengeMetadata里,这个字段是返回给客户端的公开元数据,不仅不安全,还可能导致Cognito的会话验证逻辑异常。正确的做法是只把验证码存在privateChallengeParameters(你已经做了这一步),challengeMetadata可以设置一个非敏感的标识,或者直接省略。
同时我帮你简化了重复的验证码生成逻辑:
const crypto = require("crypto"); var aws = require("aws-sdk"); var ses = new aws.SES({ region: "eu-west-2" }); exports.handler = async(event, context, callback) => { // 简化验证码生成逻辑 var verificationCode = crypto.randomInt(0, 100000).toString().padStart(6, "0"); console.log('send email'); console.log('verificationCode: '+ verificationCode); console.log('email: '+ event.request.userAttributes.email); const params = { Destination: { ToAddresses: [event.request.userAttributes.email] }, Message: { Body: { Html: { Charset: 'UTF-8', Data: `<html><body><p>This is your secret login code:</p> <h3>${verificationCode}</h3></body></html>` }, Text: { Charset: 'UTF-8', Data: `Your secret login code: ${verificationCode}` } }, Subject: { Charset: 'UTF-8', Data: 'Your secret login code' } }, Source: 'my email' }; await ses.sendEmail(params).promise().then((res) => { console.log(res); }); // 仅保留私有参数存储验证码 event.response.privateChallengeParameters = { "verificationCode": verificationCode }; // 设置非敏感的元数据标识,或直接删除该行 event.response.challengeMetadata = "EMAIL_MFA_CHALLENGE"; return event; };
3. 确保Session完整传递
虽然你已经传递了session,但要确认AdminInitiateAuthResult返回的session是完整的字符串(通常是Base64编码格式),没有被意外截断或修改。Java SDK返回的session默认是完整的,这一步主要是排查有没有额外的字符串处理逻辑破坏了session。
4. 增强Define Challenge Lambda的调试日志
在Define Challenge Lambda里添加日志输出,方便你在CloudWatch中查看会话状态,确认流程是否符合预期:
exports.handler = async(event, context, callback) => { // 添加调试日志 console.log("Current session length:", event.request.session?.length); if (event.request.session?.length > 0) { console.log("Last challenge result:", event.request.session[event.request.session.length-1].challengeResult); } if (!event.request.session || event.request.session.length === 0) { event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = 'CUSTOM_CHALLENGE'; } else if (event.request.session.length === 1 && event.request.session[0].challengeName === 'CUSTOM_CHALLENGE' && event.request.session[0].challengeResult === true) { event.response.issueTokens = true; event.response.failAuthentication = false; } else { event.response.issueTokens = false; event.response.failAuthentication = false; event.response.challengeName = 'CUSTOM_CHALLENGE'; } return event; };
总结
最可能导致session无效的原因是初始认证请求中多余的CHALLENGE_NAME参数,先修改这一步应该就能解决问题。如果还有问题,可以通过CloudWatch查看Lambda的日志,确认会话流程是否按预期执行。
内容的提问来源于stack exchange,提问作者dynamo

