簡體   English   中英

自定義生物識別提示

[英]Customize biometricPrompt

我在 android 設備中自定義 biometricPrompt 有問題。 我只使用指紋授權,但一些使用 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))

謝謝你的幫助

有點晚了,但我希望這個答案可以幫助其他開發人員。 我也試圖實現同樣的目標,最終得到了一個簡單的解決方案:

在調用.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
}

要旨

編輯:此解決方案僅在該設備上的面部掃描和/或虹膜掃描身份驗證被認為是弱方法時才有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM