配置auto_verified_attributes=["email"]后,Cognito注册用户仍未验证?
问题背景
我通过Terraform配置了LocalStack的Cognito用户池,设置了auto_verified_attributes = ["email"],期望注册用户时邮箱自动完成验证,用户状态同步变为已确认。但实际注册后,查看用户信息发现email_verified为false,UserStatus仍处于UNCONFIRMED状态。
我的Terraform用户池配置
provider "aws" { region = "us-east-1" # 可修改为需要的区域 access_key = "test" # LocalStack访问密钥 secret_key = "test" # LocalStack秘密密钥 skip_credentials_validation = true skip_requesting_account_id = true skip_metadata_api_check = true endpoints { iam = "http://localhost:4566" cognitoidp = "http://localhost:4566" } } resource "aws_cognito_user_pool" "main_user_pool" { name = "main_user_pool" account_recovery_setting { recovery_mechanism { name = "verified_email" priority = 1 } recovery_mechanism { name = "verified_phone_number" priority = 2 } } # 定义用户池属性,仅标准属性设为必填 schema { name = "email" attribute_data_type = "String" mutable = true required = true } password_policy { minimum_length = 6 require_lowercase = true require_numbers = true require_symbols = true require_uppercase = true } email_configuration { email_sending_account = "COGNITO_DEFAULT" } username_attributes = ["email"] auto_verified_attributes = ["email"] # 允许用户用邮箱或用户名登录 username_configuration { case_sensitive = true } } resource "aws_cognito_user_pool_client" "userpool_client" { name = "my-client" user_pool_id = aws_cognito_user_pool.main_user_pool.id generate_secret = false # 移动端等公开客户端无需密钥 } output "user_pool_client_id" { value = aws_cognito_user_pool_client.userpool_client.id }
Swift应用注册代码
func registerUser(email: String, password: String) { let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil) AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration let signUpRequest = AWSCognitoIdentityProviderSignUpRequest()! signUpRequest.clientId = CognitoConfig.clientId signUpRequest.username = email signUpRequest.password = password // 定义用户属性(邮箱) let emailAttribute = AWSCognitoIdentityUserAttributeType() emailAttribute?.name = "email" emailAttribute?.value = email signUpRequest.userAttributes = [emailAttribute!] // 获取服务提供者实例 let cognitoProvider = AWSCognitoIdentityProvider(forKey: "LocalStackCognito") // 执行注册 cognitoProvider.signUp(signUpRequest).continueWith { task -> AnyObject? in DispatchQueue.main.async { if let error = task.error { print("注册错误: \(error)") errorMessage = error.localizedDescription } else { print("注册成功") loginUser(email: email, password: password) } } return nil } }
配置验证与用户状态
通过awslognito-idp describe-user-pool --user-pool-id "<userpoolid>"确认用户池已正确设置AutoVerifiedAttributes: ["email"],但注册后执行awslocal cognito-idp list-users --user-pool-id "<userpoolid>",用户状态如下:
{ "Users": [ { "Username": "141bd541-2d8a-4c55-8ebd-83296e1ff99b", "Attributes": [ { "Name": "cognito:username", "Value": "test99@gmail.com" }, { "Name": "email", "Value": "test99@gmail.com" }, { "Name": "sub", "Value": "141bd541-2d8a-4c55-8ebd-83296e1ff99b" }, { "Name": "email_verified", "Value": "false" } ], "UserCreateDate": 1710631590.379655, "UserLastModifiedDate": 1710631590.379655, "Enabled": true, "UserStatus": "UNCONFIRMED" } ] }
问题原因及解决方法
核心原因:LocalStack与真实AWS Cognito的行为差异
真实AWS Cognito中,设置auto_verified_attributes后,注册时会自动发送验证邮件/短信,用户完成验证后状态自动变更;但LocalStack的Cognito模拟逻辑默认不会自动触发验证流程,也不会主动标记email_verified为true。
解决办法
方法一:手动触发用户确认与邮箱验证状态更新
注册成功后,通过命令行或代码调用Admin API完成两步操作:
- 命令行方式:
# 标记邮箱已验证 awslocal cognito-idp admin-update-user-attributes --user-pool-id <userpoolid> --username <用户sub或邮箱> --attributes Name=email_verified,Value=true # 确认用户注册 awslocal cognito-idp admin-confirm-sign-up --user-pool-id <userpoolid> --username <用户sub或邮箱>
- Swift代码方式(需确保客户端有对应Admin API权限):
// 确认用户注册 let confirmRequest = AWSCognitoIdentityProviderAdminConfirmSignUpRequest()! confirmRequest.userPoolId = CognitoConfig.userPoolId confirmRequest.username = email cognitoProvider.adminConfirmSignUp(confirmRequest).continueWith { task in if let error = task.error { print("确认用户失败: \(error)") } else { print("用户已确认") // 更新邮箱验证状态 let updateAttrsRequest = AWSCognitoIdentityProviderAdminUpdateUserAttributesRequest()! updateAttrsRequest.userPoolId = CognitoConfig.userPoolId updateAttrsRequest.username = email let verifiedAttr = AWSCognitoIdentityUserAttributeType() verifiedAttr?.name = "email_verified" verifiedAttr?.value = "true" updateAttrsRequest.userAttributes = [verifiedAttr!] cognitoProvider.adminUpdateUserAttributes(updateAttrsRequest).continueWith { updateTask in if let err = updateTask.error { print("更新邮箱验证状态失败: \(err)") } else { print("邮箱已标记为验证") loginUser(email: email, password: password) } } } return nil }
方法二:使用LocalStack Lambda触发器自动化
配置PostConfirmation类型的Lambda触发器,在用户注册完成后自动执行确认操作并更新email_verified状态。该方式适合需要全自动化的场景,但需额外配置LocalStack的Lambda环境。
方法三:检查用户池客户端配置
确保用户池客户端未限制验证流程,比如explicit_auth_flows设置正常,当前你的客户端generate_secret = false配置无问题,无需修改。
总结
LocalStack的Cognito模拟实现与真实AWS存在差异,自动验证不会自动完成,需手动触发用户确认和邮箱验证状态更新,或通过Lambda触发器实现自动化。
内容的提问来源于stack exchange,提问作者Runeaway3

