人脸身份验证,以编程方式解锁我的应用

2022-09-04 22:17:09

我正在开发一个使用指纹/面部识别来解锁应用程序的Android应用程序。

我已使用生物识别提示成功集成了指纹身份验证。但不知道从哪里开始进行面部身份验证。任何提醒都会很有帮助。

此外,由于BiostimetricPrompt带有面部,指纹和虹膜,因此我不想使用MLKIT或任何第三方库。

以下是我用于指纹身份验证的代码。

new BiometricPrompt
    .Builder(context)
    .setTitle(title)
    .setSubtitle(subtitle)
    .setDescription(description)
    .setNegativeButton(negativeButtonText, context.getMainExecutor(),
                        new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialogInterface, int i) {
            biometricCallback.onAuthenticationCancelled();
        }
    })
    .build()
    .authenticate(new CancellationSignal(), context.getMainExecutor(),
            new BiometricCallbackV28(biometricCallback));

答案 1

安卓10:将允许指纹和Face ID,就像目前在三星s10中一样。

安卓9:将只允许指纹身份验证(无论面部ID解锁是否存在)

参考链接 https://source.android.com/security/biometric/#source

编辑1:然而,三星并没有遵循谷歌的仪式。三星仍然会有不同的行为 。

1.三星 - Android 9 - 您可以选择首选的生物识别技术,这适用于应用程序。

但是有一个错误。如果禁用设备级解锁的指纹身份验证,系统将在应用级别提示您进行指纹身份验证。

  1. 三星 - Android 10 - 您可以同时保持所有身份验证处于活动状态。在生物识别提示中,您可以选择身份验证。

简短总结:

enter image description here


答案 2

第 1 步:在 build.gradle 文件中添加最新的生物识别依赖项。

implementation 'androidx.biometric:biometric:1.0.1' 

第 2 步:在 AndroidManifest.xml 文件中添加生物识别权限。

<uses-permission android:name="android.permission.USE_BIOMETRIC" />

第3步:创建activity_login.xml文件并定义触控 ID 按钮的 UI。

activity_login.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <RelativeLayout
        android:id="@+id/parent_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="30dp">

        <Button
            android:id="@+id/touch_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/river_blue"
            android:stateListAnimator="@null"
            android:text="Biometric Login"
            android:textAllCaps="false"
            android:textColor="@color/white"
            android:textSize="16sp" />

    </RelativeLayout>

</layout>

第 4 步:创建 LoginActivity.java文件以实现生物识别登录功能。

登录活动.java:

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.biometric.BiometricPrompt;
import androidx.core.content.ContextCompat;

import android.os.Build;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.widget.Button;

import androidx.biometric.BiometricManager;

import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

/**
 * Created by: rajoo.kannaujiya on 02/16/2020
 */
@RequiresApi(api = Build.VERSION_CODES.P)
public class LoginActivity extends AppCompatActivity {
    private static final String KEY_NAME = "KeyName";
    private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
    private static final String FORWARD_SLASH = "/";
    private Button touchButton;

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        touchButton = findViewById(R.id.touch_button);
        touchButton.setOnClickListener((view) -> onTouchIdClick());
        displayBiometricButton();
    }

    private void onTouchIdClick() {
        getBiometricPromptHandler().authenticate(getBiometricPrompt(), new BiometricPrompt.CryptoObject(getCipher()));
        // Please see the below mentioned note section.
        // getBiometricPromptHandler().authenticate(getBiometricPrompt());
    }

    private boolean isBiometricCompatibleDevice() {
        if (getBiometricManager().canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
            return true;
        } else {
            return false;
        }
    }

    private void displayBiometricButton() {
        if (isBiometricCompatibleDevice()) {
            touchButton.setEnabled(false);
        } else {
            touchButton.setEnabled(true);
            generateSecretKey();
        }
    }

    private BiometricManager getBiometricManager() {
        return BiometricManager.from(this);
    }

    private void generateSecretKey() {
        KeyGenerator keyGenerator = null;
        KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
                KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
                .setUserAuthenticationRequired(true)
                .setInvalidatedByBiometricEnrollment(false)
                .build();
        try {
            keyGenerator = KeyGenerator.getInstance(
                    KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
        } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
            e.printStackTrace();
        }
        if (keyGenerator != null) {
            try {
                keyGenerator.init(keyGenParameterSpec);
            } catch (InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            }
            keyGenerator.generateKey();
        }
    }

    private SecretKey getSecretKey() {
        KeyStore keyStore = null;
        Key secretKey = null;
        try {
            keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        if (keyStore != null) {
            try {
                keyStore.load(null);
            } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            try {
                secretKey = keyStore.getKey(KEY_NAME, null);
            } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
                e.printStackTrace();
            }
        }
        return (SecretKey) secretKey;
    }

    private Cipher getCipher() {
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + FORWARD_SLASH
                    + KeyProperties.BLOCK_MODE_CBC + FORWARD_SLASH
                    + KeyProperties.ENCRYPTION_PADDING_PKCS7);
            try {
                cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            e.printStackTrace();
        }
        return cipher;
    }

    private BiometricPrompt.PromptInfo getBiometricPrompt() {
        return new BiometricPrompt.PromptInfo.Builder()
                .setTitle("Biometric login for my app")
                .setSubtitle("Login with your biometric credential")
                .setNegativeButtonText("cancel")
                .setConfirmationRequired(false)
                .build();
    }

    private void onBiometricSuccess() {
        //Call the respective API on biometric success
        callLoginApi("userName", "password");
    }

    private BiometricPrompt getBiometricPromptHandler() {
        return new BiometricPrompt(this, ContextCompat.getMainExecutor(this),
                new BiometricPrompt.AuthenticationCallback() {

                    @Override
                    public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
                        super.onAuthenticationError(errorCode, errString);
                    }

                    @Override
                    public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
                        super.onAuthenticationSucceeded(result);
                        onBiometricSuccess();
                    }

                    @Override
                    public void onAuthenticationFailed() {
                        super.onAuthenticationFailed();
                    }
                }
        );
    }
}

注意:生物识别传感器(指纹、面部、虹膜)的身份验证级别分为。根据 Android 兼容性定义文档 (Android CDD),要访问 Android 密钥存储,生物识别传感器的身份验证级别必须分类为“强”。由于面部和虹膜传感器在某些设备中被归类为类别,因此在这些设备中,面部和虹膜选项将不会显示在使用CryptoObject进行身份验证的生物识别提示中。

getBiometricPromptHandler().authenticate(getBiometricPrompt(), new BiometricPrompt.CryptoObject(getCipher()));

如果您在没有CryptoObject的情况下对生物识别提示进行身份验证,则将显示它。

getBiometricPromptHandler().authenticate(getBiometricPrompt());

推荐