You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

含敏感信息的Android应用强制用户每次登录验证密码短语/指纹的实现问询

当然有!Android官方提供的BiometricPrompt(配合AndroidX兼容库)就是专门解决这类身份验证需求的方案,既支持指纹/面部等生物识别,也允许用户用系统密码/PIN/图案验证,完全符合你要的“每次启动必须验证”的要求。下面给你捋清楚具体实现步骤和要点:

核心思路

我们的目标是:应用启动(或从后台切回前台)时,先触发系统级的身份验证流程,只有验证通过后,用户才能访问应用内的敏感内容。BiometricPrompt会自动处理系统层面的验证UI和安全逻辑,不需要我们自己造轮子,既安全又省心。

具体实现步骤

1. 添加依赖

首先在你的app模块的build.gradle(或build.gradle.kts)中引入AndroidX的Biometric库,它能帮我们处理低版本Android的兼容问题:

dependencies {
    implementation "androidx.biometric:biometric:1.1.0"
}

2. 设计验证触发时机

通常我们会在应用的启动页(SplashActivity)或者主界面的onCreate/onResume方法中触发验证流程:

  • 如果是启动页:应用打开后直接显示验证弹窗,验证通过再跳转到主界面;
  • 如果是主界面:每次应用从后台切回前台时(onResume)都触发验证,防止用户离开后他人随意访问。

3. 构建BiometricPrompt实例

我们需要配置验证提示信息,并实现验证结果的回调:

  • PromptInfo:设置弹窗的标题、副标题,以及允许的验证方式(生物识别+设备凭据);
  • AuthenticationCallback:处理验证成功、失败、错误的情况。

4. 检查设备支持情况

在启动验证前,先通过BiometricManager检查设备是否支持我们需要的验证方式,比如是否有生物识别硬件、用户是否已注册指纹/密码等。

完整代码示例(Kotlin)

这里以启动页为例,实现“打开应用就必须验证”的逻辑:

class SplashActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_splash)

        // 初始化主线程执行器(Biometric回调会在这个线程执行)
        val mainExecutor = ContextCompat.getMainExecutor(this)

        // 创建BiometricPrompt实例及回调
        val biometricPrompt = BiometricPrompt(this, mainExecutor, object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
                // 验证成功,跳转到主界面
                startActivity(Intent(this@SplashActivity, MainActivity::class.java))
                finish()
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                Toast.makeText(this@SplashActivity, "验证失败,请重试", Toast.LENGTH_SHORT).show()
            }

            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)
                when (errorCode) {
                    BiometricPrompt.ERROR_NEGATIVE_BUTTON -> {
                        // 用户点击取消,退出应用
                        finish()
                    }
                    BiometricPrompt.ERROR_NO_BIOMETRICS, BiometricPrompt.ERROR_NONE_ENROLLED -> {
                        // 引导用户去设置验证方式
                        navigateToBiometricSettings()
                    }
                    else -> {
                        Toast.makeText(this@SplashActivity, "验证出错:$errString", Toast.LENGTH_SHORT).show()
                        finish()
                    }
                }
            }
        })

        // 配置验证弹窗信息
        val promptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle("身份验证")
            .setSubtitle("请验证指纹或输入系统密码以访问应用")
            // 允许强生物识别 + 设备凭据(密码/PIN/图案)
            .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
            .build()

        // 检查设备是否支持验证方式
        val biometricManager = BiometricManager.from(this)
        when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)) {
            BiometricManager.BIOMETRIC_SUCCESS -> {
                // 支持,启动验证
                biometricPrompt.authenticate(promptInfo)
            }
            BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
                Toast.makeText(this, "设备不支持生物识别或密码验证", Toast.LENGTH_SHORT).show()
                finish()
            }
            BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
                Toast.makeText(this, "验证硬件暂时不可用", Toast.LENGTH_SHORT).show()
                finish()
            }
            BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
                // 用户未注册任何验证方式,引导去设置
                navigateToBiometricSettings()
            }
        }
    }

    /**
     * 跳转到系统生物识别设置页面
     */
    private fun navigateToBiometricSettings() {
        val enrollIntent = Intent(Settings.ACTION_BIOMETRIC_ENROLL).apply {
            putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED,
                BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
        }
        startActivityForResult(enrollIntent, REQUEST_CODE_ENROLL)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE_ENROLL) {
            // 用户从设置返回后,重新检查并启动验证
            val biometricManager = BiometricManager.from(this)
            if (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS) {
                // 重新初始化BiometricPrompt并启动验证
                val mainExecutor = ContextCompat.getMainExecutor(this)
                val biometricPrompt = BiometricPrompt(this, mainExecutor, object : BiometricPrompt.AuthenticationCallback() {
                    override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                        super.onAuthenticationSucceeded(result)
                        startActivity(Intent(this@SplashActivity, MainActivity::class.java))
                        finish()
                    }
                })
                val promptInfo = BiometricPrompt.PromptInfo.Builder()
                    .setTitle("身份验证")
                    .setSubtitle("请验证指纹或输入系统密码以访问应用")
                    .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
                    .build()
                biometricPrompt.authenticate(promptInfo)
            } else {
                Toast.makeText(this, "未设置验证方式,无法进入应用", Toast.LENGTH_SHORT).show()
                finish()
            }
        }
    }

    companion object {
        private const val REQUEST_CODE_ENROLL = 1001
    }
}

关键注意事项

  1. 安全优先级:不要自己存储密码短语,完全依赖系统的身份验证机制——BiometricPrompt的验证是系统级的,比我们自己实现的密码输入框安全得多;
  2. 敏感数据存储:验证通过后,敏感信息建议存在Android Keystore中,用密钥加密存储,只有验证通过后才能解密使用,进一步提升安全性;
  3. 后台切回验证:如果需要用户切回应用也验证,只需在MainActivity的onResume方法中重复上述验证逻辑即可;
  4. 权限问题:Android 10及以上不需要额外权限,Android 9及以下需添加USE_BIOMETRIC权限到Manifest中,但AndroidX库会自动处理兼容。

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

火山引擎 最新活动