Firebase Auth修改密码重认证提示自定义令牌格式错误排查
问题根因
你遇到的两个报错都来自两个核心错误:
- 操作顺序完全不符合Firebase Auth的安全规则
- 重认证场景用错了API,传入的令牌类型和接口要求不匹配
具体错误说明
- 顺序错误:修改密码属于高敏感操作,Firebase要求必须先完成重新认证,再执行密码修改,你现在先调用改密接口再做重认证,当用户登录会话留存时间超过安全阈值时,就会直接触发
You need to log in to change your password报错,哪怕用户本地显示是登录状态。 - API误用:
signInWithCustomToken()接口仅接受服务端通过Firebase Admin SDK生成的自定义签名令牌,你通过getAccessToken(true)拿到的是客户端已登录用户的访问ID令牌,两种令牌的签名规则、格式完全不同,传入后必然触发The custom token format is incorrect错误。 - 无独立服务端的纯客户端场景下,根本不需要用自定义令牌做重认证,也不需要提前刷新访问令牌。
正确实现方案
正确操作流程
- 收集用户输入的当前账号旧密码和待设置的新密码
- 用当前登录账号的邮箱+旧密码生成邮箱登录凭证
- 调用重认证接口传入凭证,完成身份校验
- 重认证通过后,再调用密码更新接口设置新密码
- 改密完成后如果业务需要最新令牌,再主动刷新访问令牌即可(非必须,Firebase会自动同步本地会话状态)
修正后的代码
// 替换原来错误的重认证逻辑,不需要传刷新后的token private fun reAuthenticate(email: String, oldPassword: String): Completable { return Completable.create { emitter -> // 生成邮箱密码登录的认证凭证 val credential = EmailAuthProvider.getCredential(email, oldPassword) Firebase.auth.currentUser ?.reauthenticate(credential) ?.addOnCompleteListener { task -> if (task.isSuccessful) { emitter.onComplete() } else { emitter.onError(task.exception ?: Throwable("重认证失败")) } } ?: emitter.onError(Throwable("当前无登录用户")) } } private fun updatePassword(newPassword: String): Single<Boolean> { return Single.create { emitter -> Firebase.auth.currentUser?.updatePassword(newPassword) ?.addOnCompleteListener { task -> emitter.onSuccess(task.isSuccessful) } ?: emitter.onSuccess(false) } } // 改密完成后如果需要新令牌再调用,不是重认证的前置步骤 private fun getNewToken(): Single<String> { return Single.create { emitter -> Firebase.auth.getAccessToken(true) .addOnCompleteListener { task -> if (task.isSuccessful) { task.result.token?.let { emitter.onSuccess(it) } ?: emitter.onError(Throwable("获取令牌失败")) } else { emitter.onError(task.exception ?: Throwable("刷新令牌失败")) } } } } // 业务调用逻辑 private fun changePassword(oldPassword: String, newPassword: String) { // 从当前登录用户信息中获取邮箱 val currentUserEmail = Firebase.auth.currentUser?.email ?: return reAuthenticate(currentUserEmail, oldPassword) .andThen(updatePassword(newPassword)) // 不需要新令牌可以删掉下面这行 .flatMap { getNewToken() } .subscribe( { println("密码修改成功") }, { println("操作失败: ${it.message}") } ) }
注意:新密码需要符合Firebase的密码强度要求,默认最少6位,你示例里的
pass12345符合规则。
内容的提问来源于stack exchange,提问作者No Name
相关产品推荐
相关产品推荐

