Amplify预注册Lambda如何访问修改用户sub属性与username
场景背景
Amplify默认集成的Cognito用户池存在如下双用户名设计缺陷:
- 平台原生支持用户通过
preferred_username作为凭证登录 - 注册阶段强制要求传入的用户名并非
preferred_username,且该初始注册用户名为永久不可变属性 - 用户完成邮箱验证后才可设置
preferred_username,后续只要该值未被其他用户占用就支持修改 - 配置完成后用户支持三种登录方式:注册时填写的不可变系统用户名、绑定邮箱、验证后设置的可变
preferred_username
该设计会导致同一用户对应两个独立的用户名标识,对终端用户存在认知负担,也不符合产品侧仅让用户感知单一登录ID的需求。
预期实现目标
- 在pre-signup(预注册)Lambda触发器中获取长度为32位的唯一用户ID,即Cognito原生
sub属性 - 注册阶段不采集用户手动输入的用户名,改为自动传入UUID作为系统层占位用户名,用户全程仅需感知
preferred_username这一个登录标识 - 在Lambda逻辑中实现
sub与系统username值统一:要么将自定义UUID格式的username赋值给sub,如果无法修改sub则将Cognito生成的sub值反向赋值给username,消除两个系统ID不一致的问题
问题解答
1. 预注册Lambda是否支持访问/修改sub属性?
结论:不支持,你碰到的Cannot read properties of undefined报错为预期行为,不存在可直接在预注册阶段访问或修改sub的方案。
原因很明确:sub是Cognito用户池为每个用户生成的全局唯一只读标识,只有用户记录成功持久化写入用户池之后才会完成分配。预注册Lambda触发时,用户记录还处于规则校验的临时状态,尚未完成创建,事件对象中根本不会携带sub字段,且该属性为Cognito内部托管字段,即使用户创建完成后,在任何触发器中也仅支持读取、不支持修改。
替代实现路径:无需强行对齐Cognito原生sub,可在预注册Lambda中自行生成符合格式要求的32位无横杠UUID作为业务层唯一用户ID,在用户确认注册后将该值写入自定义用户属性(例如custom:internal_uid),业务侧所有用户关联逻辑统一使用该自定义ID即可。
2. 预注册Lambda是否支持修改username字段?
结论:不支持,你碰到的Invalid user name. User name in Lambda mismatches the actual username.报错是Cognito的强制校验规则导致,不存在直接在预注册Lambda中修改username绕过校验的方案。
预注册触发器事件中携带的userName字段为只读透传字段,Lambda返回结果时Cognito会强制校验返回的userName与注册请求传入的原始值完全一致,一旦检测到修改就会直接拦截注册流程抛出错误。
可行替代方案:
- 前端注册流程完全移除用户名输入项,注册请求发起前在前端直接生成符合Cognito格式要求的UUID字符串作为
username参数传入,用户全程无感知 - 预注册Lambda仅做
preferred_username的格式校验、唯一性校验,透传自动生成的username字段不做修改 - 如果必须实现
username与sub值完全一致,放弃前端直接调用注册接口的流程,改为后端调用AdminCreateUser接口创建用户:调用时不主动传入username参数,Cognito会自动生成与sub值完全相同的用户名,整个逻辑在后端完成,前端无需参与
3. 该方案在社交登录场景下的适配限制
上述改造方案在第三方社交(联邦)登录场景下存在3个明确的适配限制:
- 社交登录首次触发时,Cognito会自动为联邦用户生成系统
username,格式为[身份提供商名称]_[第三方平台返回的用户唯一ID],无法在预注册阶段替换该自动生成值,也无法干预sub的生成逻辑 - 社交登录流程不会自动填充
preferred_username字段,需要在Post Authentication(认证后)触发器中判断用户是否为首次登录,首次登录时强制跳转到资料补充页引导用户设置preferred_username,同时完成唯一性校验 - 若用户池同时开启用户名密码登录和社交登录,会出现两类用户系统
username格式不统一的问题:自注册用户为自动生成的UUID,社交登录用户为Cognito生成的第三方拼接ID,业务层做用户数据关联时必须统一使用sub或自定义的custom:internal_uid作为关联键,禁止使用username做关联
内容的提问来源于stack exchange,提问作者ThinQ

