You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

配置AWS Cognito用户池迁移后遇验证错误求助

AWS Cognito用户池迁移触发器无日志且报错:No email provided but email_verified was true & UserNotFoundException

问题背景

已完成两个AWS Cognito用户池的迁移配置,操作步骤:

  • 基于官方迁移示例创建Lambda函数
  • 在目标用户池配置迁移触发器并关联该Lambda
  • 为相关IAM角色添加对应权限策略

测试时出现两个核心问题:

  1. Cognito返回错误提示:No email provided but email_verified was true
  2. 迁移触发器Lambda未生成CloudWatch日志,同时客户端收到UserNotFoundException响应

相关代码片段

用户登录代码

const authenticationData = {
    Username: email,
    Email: email,
    Password: userPassword,
};

const authDetails = AWS.authenticationDetails(authenticationData);
const userPool = AWS.cognitoUserPool(poolData);
const userData = {
    Username: email,
    Email: email,
    Pool: userPool,
};
const cognitoUser = AWS.cognitoUser(userData);
cognitoUser.setAuthenticationFlowType('USER_PASSWORD_AUTH');
authDetails.email = email;
try {
    const authResult = await utilsHelper.promisifySF(cognitoUser.authenticateUser.bind(cognitoUser))(authDetails);
    console.log('authResult : ', authResult);
} catch (e) {
    console.log('user verify exception : ', e);
}

Lambda迁移函数代码

'use strict';
var CLIENT_ID = '';
var USER_POOL_ID = '';
var OLD_CLIENT_ID = '';
var OLD_USER_POOL_ID = '';
var OLD_USER_POOL_REGION = '';
var OLD_ROLE_ARN = '';
var OLD_EXTERNAL_ID = '';
var AWS = require('aws-sdk');
exports.handler = (event, context, callback) => {

    var user;

    if ( event.triggerSource == "UserMigration_Authentication" ) {

        // authenticate the user with your existing user directory service
        user = authenticateUser(event.userName, event.request.password);
        if ( user ) {
            event.response.userAttributes = {
                "email": user.emailAddress,
                "email_verified": "true"
            };
            event.response.finalUserStatus = "CONFIRMED";
            event.response.messageAction = "SUPPRESS";
            context.succeed(event);
        }
        else {
            // Return error to Amazon Cognito
            callback("Bad password");
        }
    }
    else { 
        // Return error to Amazon Cognito
        callback("Bad triggerSource " + event.triggerSource);
    }
};
async function authenticateUser(username, password) {
  const isp = new AWS.CognitoIdentityServiceProvider();
  // Validate username/password
  const resAuth = await isp.adminInitiateAuth({
    AuthFlow: 'ADMIN_USER_PASSWORD_AUTH',
    AuthParameters: {
      PASSWORD: password,
      USERNAME: username,
    },
    ClientId: OLD_CLIENT_ID,
    UserPoolId: OLD_USER_POOL_ID,
  }).promise();
  if (resAuth.code && resAuth.message) {
    return undefined;
  }
  // Load user data
  const resGet = await isp.adminGetUser({
    UserPoolId: OLD_USER_POOL_ID,
    Username: username,
  }).promise();
  if (resGet.code && resGet.message) {
    return undefined;
  } 
  return {
    emailAddress: resGet.UserAttributes.find(e => e.Name === 'email').Value,
  };
}

客户端错误响应

{
  "code": "UserNotFoundException",
  "name": "UserNotFoundException",
  "message": "User does not exist."
}

问题排查与修复方案

1. Lambda无日志+UserNotFoundException:迁移触发器未触发

这两个问题的核心是Cognito根本没有触发迁移流程,需检查以下配置:

  • 目标用户池客户端认证流程:确保目标用户池的客户端已启用ALLOW_USER_PASSWORD_AUTH流程(在用户池客户端的「认证流程」设置中勾选)
  • 迁移触发器状态:确认目标用户池的「触发器」配置里,「用户迁移」已关联正确的Lambda函数且状态为启用
  • 用户名匹配规则:如果旧池的用户名不是邮箱格式,而你用邮箱作为登录用户名,Cognito无法匹配触发迁移,需保证新旧池的用户名规则一致

2. No email provided but email_verified was true:Lambda异步处理缺陷

当前Lambda handler存在异步调用错误:authenticateUser是异步函数,但handler中同步调用导致user始终是Promise对象,无法正确设置用户属性。修复后的Lambda代码:

'use strict';
var OLD_CLIENT_ID = ''; // 填写旧池客户端ID
var OLD_USER_POOL_ID = ''; // 填写旧池ID
var OLD_USER_POOL_REGION = ''; // 填写旧池区域
var AWS = require('aws-sdk');
const isp = new AWS.CognitoIdentityServiceProvider({ region: OLD_USER_POOL_REGION });

exports.handler = async (event) => {
    if (event.triggerSource !== "UserMigration_Authentication") {
        throw new Error("Bad triggerSource " + event.triggerSource);
    }

    try {
        const user = await authenticateUser(event.userName, event.request.password);
        if (!user) {
            throw new Error("Bad password");
        }
        event.response.userAttributes = {
            "email": user.emailAddress,
            "email_verified": "true"
        };
        event.response.finalUserStatus = "CONFIRMED";
        event.response.messageAction = "SUPPRESS";
        return event;
    } catch (err) {
        throw err;
    }
};

async function authenticateUser(username, password) {
    try {
        await isp.adminInitiateAuth({
            AuthFlow: 'ADMIN_USER_PASSWORD_AUTH',
            AuthParameters: {
                PASSWORD: password,
                USERNAME: username,
            },
            ClientId: OLD_CLIENT_ID,
            UserPoolId: OLD_USER_POOL_ID,
        }).promise();

        const resGet = await isp.adminGetUser({
            UserPoolId: OLD_USER_POOL_ID,
            Username: username,
        }).promise();

        const emailAttr = resGet.UserAttributes.find(e => e.Name === 'email');
        if (!emailAttr) {
            throw new Error("User has no email attribute");
        }
        return {
            emailAddress: emailAttr.Value
        };
    } catch (err) {
        console.error("Authenticate user failed:", err);
        return undefined;
    }
}

3. 额外优化与检查

  • Lambda权限补充:确保Lambda角色拥有cognito-idp:AdminInitiateAuth、cognito-idp:AdminGetUser权限,以及CloudWatch日志的logs:CreateLogGroup、logs:CreateLogStream、logs:PutLogEvents权限
  • 登录代码修正:AWS SDK调用方式有误,正确写法如下:
const authenticationData = {
    Username: email,
    Password: userPassword,
};
const authDetails = new AWS.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
const userPool = new AWS.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
const userData = {
    Username: email,
    Pool: userPool,
};
const cognitoUser = new AWS.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.setAuthenticationFlowType('USER_PASSWORD_AUTH');

无需手动设置authDetails.email,Username已传入邮箱信息

内容的提问来源于stack exchange,提问作者Michael Marshal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:39:19