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

Flutter原生调用Android KeyStore密钥未触发身份验证问题求助

解决方案:通过BiometricPrompt触发身份验证后使用KeyStore密钥签名

可以实现,问题出在你直接使用KeyStore中的私钥进行签名,没有触发Android的身份验证流程。KeyStore要求这类受保护的密钥必须在用户验证通过后才能使用,所以需要借助BiometricPrompt完成身份验证,获取经过授权的密钥实例后再执行签名操作。

实现步骤:

  • 先检查设备是否支持生物识别或设备凭据验证
  • 创建BiometricPrompt并配置验证弹窗信息,绑定签名用的CryptoObject
  • 在验证成功的回调中,使用授权后的密钥执行签名操作
  • 通过自定义回调将签名结果返回给Flutter侧

完整示例代码

1. 确保依赖配置(build.gradle)

implementation "androidx.biometric:biometric:1.1.0"

2. 签名逻辑实现(MainActivity.kt)

import android.security.keystore.KeyStore
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import java.security.PrivateKey
import java.security.Signature

// 定义回调接口,用于向Flutter传递签名结果
interface SignResultCallback {
    fun onSignatureSuccess(signedData: ByteArray)
    fun onSignatureFailed(errorMsg: String)
}

class MainActivity : FlutterActivity() {
    private var currentCallback: SignResultCallback? = null

    // 暴露给Flutter的签名方法
    fun startSigning(dataToSign: ByteArray, callback: SignResultCallback) {
        currentCallback = callback
        checkAuthenticationSupport(dataToSign)
    }

    private fun checkAuthenticationSupport(data: ByteArray) {
        val biometricManager = BiometricManager.from(this)
        val authTypes = BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL

        when (biometricManager.canAuthenticate(authTypes)) {
            BiometricManager.BIOMETRIC_SUCCESS -> launchBiometricPrompt(data)
            else -> currentCallback?.onSignatureFailed("设备不支持生物识别或设备凭据验证")
        }
    }

    private fun launchBiometricPrompt(data: ByteArray) {
        try {
            // 初始化Signature实例,关联KeyStore中的密钥
            val signature = Signature.getInstance("SHA256withECDSA")
            val keyStore = KeyStore.getInstance("AndroidKeyStore")
            keyStore.load(null)
            val privateKey = keyStore.getKey("xxx", null) as PrivateKey
            signature.initSign(privateKey)

            // 绑定Signature到CryptoObject
            val cryptoObject = BiometricPrompt.CryptoObject(signature)

            // 配置验证弹窗信息
            val promptInfo = BiometricPrompt.PromptInfo.Builder()
                .setTitle("身份验证")
                .setSubtitle("请验证身份以完成签名")
                .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
                .build()

            // 创建BiometricPrompt并启动验证
            val executor = ContextCompat.getMainExecutor(this)
            val biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
                override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                    super.onAuthenticationSucceeded(result)
                    result.cryptoObject?.signature?.let { authSignature ->
                        try {
                            authSignature.update(data)
                            val signedBytes = authSignature.sign()
                            currentCallback?.onSignatureSuccess(signedBytes)
                        } catch (e: Exception) {
                            currentCallback?.onSignatureFailed("签名失败:${e.message}")
                        }
                    } ?: currentCallback?.onSignatureFailed("无法获取授权的签名实例")
                }

                override fun onAuthenticationFailed() {
                    super.onAuthenticationFailed()
                    currentCallback?.onSignatureFailed("身份验证失败")
                }

                override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                    super.onAuthenticationError(errorCode, errString)
                    currentCallback?.onSignatureFailed("验证错误:$errString")
                }
            })

            biometricPrompt.authenticate(promptInfo, cryptoObject)
        } catch (e: Exception) {
            currentCallback?.onSignatureFailed("初始化签名流程失败:${e.message}")
        }
    }

    // 你的密钥生成代码...
}

核心说明:

  • CryptoObject绑定:将Signature实例与BiometricPrompt绑定后,验证通过时KeyStore会自动授权该实例使用受保护的私钥,避免直接调用未授权密钥抛出异常。
  • 验证类型匹配:弹窗配置的AllowedAuthenticators与密钥生成时的AUTH_DEVICE_CREDENTIAL or AUTH_BIOMETRIC_STRONG保持一致,确保验证方式兼容。
  • Flutter通信:通过SignResultCallback结合MethodChannel,可将签名结果无缝传递给Flutter侧调用方。

内容的提问来源于stack exchange,提问作者user2801516

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:11:00