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

Firebase Auth修改密码重认证提示自定义令牌格式错误排查

问题根因

你遇到的两个报错都来自两个核心错误:

  • 操作顺序完全不符合Firebase Auth的安全规则
  • 重认证场景用错了API,传入的令牌类型和接口要求不匹配

具体错误说明

  1. 顺序错误:修改密码属于高敏感操作,Firebase要求必须先完成重新认证,再执行密码修改,你现在先调用改密接口再做重认证,当用户登录会话留存时间超过安全阈值时,就会直接触发You need to log in to change your password报错,哪怕用户本地显示是登录状态。
  2. API误用:signInWithCustomToken()接口仅接受服务端通过Firebase Admin SDK生成的自定义签名令牌,你通过getAccessToken(true)拿到的是客户端已登录用户的访问ID令牌,两种令牌的签名规则、格式完全不同,传入后必然触发The custom token format is incorrect错误。
  3. 无独立服务端的纯客户端场景下,根本不需要用自定义令牌做重认证,也不需要提前刷新访问令牌。
正确实现方案

正确操作流程

  • 收集用户输入的当前账号旧密码和待设置的新密码
  • 用当前登录账号的邮箱+旧密码生成邮箱登录凭证
  • 调用重认证接口传入凭证,完成身份校验
  • 重认证通过后,再调用密码更新接口设置新密码
  • 改密完成后如果业务需要最新令牌,再主动刷新访问令牌即可(非必须,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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:57:19