AWS Cognito用户池自定义认证流iOS实现的重复调用疑问
为什么AWS Cognito自定义认证流中会出现两次
set(result: details)调用? 我来帮你梳理下这个问题——你遇到的两次调用set(result: details)的情况,其实是因为对Cognito自定义认证的iOS端流程逻辑理解有偏差,咱们一步步拆解:
问题根源:对getCustomChallengeDetails触发时机的错误处理
Cognito自定义认证在iOS端的AWSCognitoIdentityCustomAuthentication处理器中,getCustomChallengeDetails会被触发两次,但两次的作用完全不同:
- 第一次触发:此时
challengeParameters为空,这是Cognito发起的初始挑战请求——它在询问客户端:「你是否准备好接收自定义挑战?」。这时候你不需要提交任何验证码,而是应该触发「发送验证码到用户邮箱」的逻辑,同时弹出验证码输入UI等待用户输入。 - 第二次触发:当后端触发器完成验证码发送后,Cognito会再次调用这个方法(此时
challengeParameters会带上会话等必要参数),这一步通常不需要直接提交结果,真正的提交应该由用户输入验证码后手动触发。
而你的代码里,在challengeParameters.count > 0的第二次调用时,自动取了输入框的内容提交了一次;之后用户点击提交按钮时又手动调用了一次,所以出现了两次重复提交!
正确的处理流程
你需要把「自动提交」和「用户手动提交」的逻辑彻底分开:
1. 修正getCustomChallengeDetails的逻辑
只负责初始化、触发验证码发送和弹出输入UI,不自动提交结果:
func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) { self.customAuthenticationCompletion = customAuthCompletionSource if authenticationInput.challengeParameters.isEmpty { // 第一次调用:触发后端发送验证码的逻辑 self.sendVerificationCodeToUser() // 弹出验证码输入界面 DispatchQueue.main.async { self.present(self.codeInputVC, animated: true) } } else { // 第二次调用:可以读取challengeParameters中的会话信息(如果触发器需要),但不要自动提交验证码 // 比如 let session = authenticationInput.challengeParameters["SESSION"] } }
2. 用户手动提交验证码时再调用set(result:)
只有当用户输入完成并主动点击提交按钮时,才执行提交操作:
@IBAction func submitCodeTapped(_ sender: UIButton) { guard let code = codeTextField.text, !code.isEmpty else { // 提示用户输入验证码 return } let details = AWSCognitoIdentityCustomChallengeDetails( challengeResponses: ["CODE": code]) details.initialChallengeName = "CUSTOM_CHALLENGE" self.customAuthenticationCompletion?.set(result: details) self.dismiss(animated: true) }
补充说明:关于didCompleteStepWithError
你提到的这个方法确实容易误导人——它不管认证步骤成功还是失败都会被调用:
- 当步骤成功时,
error为nil,你可以在这里处理后续逻辑(比如跳转到主界面) - 当步骤失败时,
error会包含具体错误信息(比如验证码错误),你可以在这里提示用户重新输入
这样修改后,就只会有一次有效的验证码提交调用,也就是用户手动触发的那次,彻底避免了重复提交的问题。
内容的提问来源于stack exchange,提问作者Carl
相关产品推荐
相关产品推荐

