自定义 biometricPrompt
Posted
技术标签:
【中文标题】自定义 biometricPrompt【英文标题】:Customize biometricPrompt 【发布时间】:2019-08-16 14:01:31 【问题描述】:我在 android 设备中 时遇到问题。我只使用指纹授权,但一些具有 android 9.0 的设备(例如三星 Galaxy S10+)授权使用指纹(如果允许)但与面部身份验证相同。如果用户同时允许面部和指纹认证 biometricPrompt 用于认证面部识别。我只需要允许指纹,如果用户不允许指纹但面部是的,我需要阻止它。
文档告诉我这个(来自docs)
...但没有任何指示,我在源代码中找不到任何关于自定义的内容。
我的启动代码身份验证对话框在这里
BiometricPrompt.Builder(context)
.setTitle(biometricBuilder.title ?: "")
.setSubtitle(biometricBuilder.subtitle ?: "")
.setDescription(biometricBuilder.description ?: "")
.setNegativeButton(biometricBuilder.negativeButtonText ?: "",
context.mainExecutor, DialogInterface.OnClickListener dialogInterface, i -> biometricCallback.onAuthenticationCancelled() )
.build()
.authenticate(CancellationSignal(), context.mainExecutor,
BiometricCallbackV28(biometricCallback))
感谢您的帮助
【问题讨论】:
很遗憾,这不受支持。您所指的文档适用于设备制造商,而不是应用程序开发人员。它只是说最终用户应该能够在“设置”应用中手动选择他们喜欢的生物特征。 所以当我只想要指纹时无法使用 BiometricPrompt? 暂时没有。我在去年 filed an issue 谈到了这个问题,但还没有收到任何有意义的回复。 你对这个问题有一些解决方案(首选一次身份验证并阻止第二次)或同时使用(指纹和面部) 目前使用BiometricPrompt
时无解析。如果你只想允许指纹,你可以使用FingerprintManager
(它已被弃用,但这并不意味着它已被删除)。
【参考方案1】:
有点晚了,但我希望这个答案可以帮助其他开发人员。 我也试图实现同样的目标,最终得到了一个简单的解决方案:
像这样调用.authenticate()
时提供一个加密对象:
/**
* Prerequisites:
* 1. Add
* `implementation "androidx.biometric:biometric:1.0.1"` in build.gradle
* 2. Add
* ` <uses-permission android:name="android.permission.USE_BIOMETRIC" android:requiredFeature="false"/>`
* in AndroidManifest.xml
*/
object BiometricHelper
private const val ENCRYPTION_BLOCK_MODE = KeyProperties.BLOCK_MODE_GCM
private const val ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_NONE
private const val ENCRYPTION_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES
private const val KEY_SIZE = 128
private lateinit var biometricPrompt: BiometricPrompt
fun authenticate(fragmentActivity: FragmentActivity, authCallback: BiometricPrompt.AuthenticationCallback)
try
if (!fragmentActivity.supportFragmentManager.executePendingTransactions())
biometricPrompt = createBiometricPrompt(fragmentActivity, authCallback)
val promptInfo = createPromptInfo()
biometricPrompt.authenticate(
promptInfo,
cryptoObject //Providing crypto object here will block Iris and Face Scan
)
catch (e: KeyPermanentlyInvalidatedException)
e.printStackTrace()
catch (e: Exception)
e.printStackTrace()
private fun createBiometricPrompt(fragmentActivity: FragmentActivity, authCallback: BiometricPrompt.AuthenticationCallback): BiometricPrompt
val executor = ContextCompat.getMainExecutor(fragmentActivity)
return BiometricPrompt(fragmentActivity, executor, authCallback)
private fun createPromptInfo(): BiometricPrompt.PromptInfo
return BiometricPrompt.PromptInfo.Builder()
.setTitle("Authentication")
.setConfirmationRequired(false)
.setNegativeButtonText("Cancel")
.setDeviceCredentialAllowed(false) //Don't Allow PIN/pattern/password authentication.
.build()
//endregion
//====================================================================================
//region Dummy crypto object that is used just to block Face, Iris scan
//====================================================================================
/**
* Crypto object requires STRONG biometric methods, and currently Android considers only
* FingerPrint auth is STRONG enough. Therefore, providing a crypto object while calling
* [androidx.biometric.BiometricPrompt.authenticate] will block Face and Iris Scan methods
*/
private val cryptoObject by lazy
getDummyCryptoObject()
private fun getDummyCryptoObject(): BiometricPrompt.CryptoObject
val transformation = "$ENCRYPTION_ALGORITHM/$ENCRYPTION_BLOCK_MODE/$ENCRYPTION_PADDING"
val cipher = Cipher.getInstance(transformation)
var secKey = getOrCreateSecretKey(false)
try
cipher.init(Cipher.ENCRYPT_MODE, secKey)
catch (e: KeyPermanentlyInvalidatedException)
e.printStackTrace()
secKey = getOrCreateSecretKey(true)
cipher.init(Cipher.ENCRYPT_MODE, secKey)
catch (e: Exception)
e.printStackTrace()
return BiometricPrompt.CryptoObject(cipher)
private fun getOrCreateSecretKey(mustCreateNew: Boolean): SecretKey
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
if (!mustCreateNew)
keyStore.getKey("dummyKey", null)?.let return it as SecretKey
val paramsBuilder = KeyGenParameterSpec.Builder("dummyKey",
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
paramsBuilder.apply
setBlockModes(ENCRYPTION_BLOCK_MODE)
setEncryptionPaddings(ENCRYPTION_PADDING)
setKeySize(KEY_SIZE)
setUserAuthenticationRequired(true)
val keyGenParams = paramsBuilder.build()
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
"AndroidKeyStore")
keyGenerator.init(keyGenParams)
return keyGenerator.generateKey()
//endregion
Gist
编辑: 仅当该设备上的面部扫描和/或虹膜扫描身份验证被视为 WEAK 方法时,此解决方案才有效。
【讨论】:
//Providing crypto object here will block Iris and Face Scan
无法保证。这完全取决于设备的哪个生物识别传感器被归类为 STRONG。
确实如此。我忘了提。以上是关于自定义 biometricPrompt的主要内容,如果未能解决你的问题,请参考以下文章