Android(安卓)在应用中使用用户凭证(PIN码、密码)
16lz
2022-06-30
Android 在应用中使用用户凭证(PIN码、密码)
在Android开发过程需要使用到用户凭证来验证用户身份,验证成功用户才能继续操作。需要注意的是:minSdkVersion 必须大于或等于23,否则APP会报错。
先上效果图(在30s内不操作,点击确认按钮需要进行身份验证):
以下是activity代码
import android.app.Activity;import android.app.KeyguardManager;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.security.keystore.KeyGenParameterSpec;import android.security.keystore.KeyPermanentlyInvalidatedException;import android.security.keystore.KeyProperties;import android.security.keystore.UserNotAuthenticatedException;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import java.io.IOException;import java.security.InvalidAlgorithmParameterException;import java.security.InvalidKeyException;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.BadPaddingException;import javax.crypto.Cipher;import javax.crypto.IllegalBlockSizeException;import javax.crypto.KeyGenerator;import javax.crypto.NoSuchPaddingException;import javax.crypto.SecretKey;public class CertificateActivity extends Activity{ /** Alias for our key in the Android Key Store. */ private static final String KEY_NAME = "my_key"; private static final byte[] SECRET_BYTE_ARRAY = new byte[] {1, 2, 3, 4, 5, 6}; private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 1; /** * 如果用户在最近的几秒钟内解锁了设备, *它可以视为身份验证者。 */ private static final int AUTHENTICATION_DURATION_SECONDS = 30; private KeyguardManager mKeyguardManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_certificate); mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); Button purchaseButton = (Button) findViewById(R.id.purchase_button); if (!mKeyguardManager.isKeyguardSecure()) { // Show a message that the user hasn't set up a lock screen. Toast.makeText(this, "没有设置设备锁定密码。\n" + "请去'设置 -> 安全 -> 屏幕锁定' 进行屏幕锁定设置!", Toast.LENGTH_LONG).show(); purchaseButton.setEnabled(false); return; } createKey(); findViewById(R.id.purchase_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Test to encrypt something. It might fail if the timeout expired (30s). tryEncrypt(); } }); } /** * 尝试使用{@link #createKey}中生成的密钥加密某些数据 *仅在用户刚刚通过设备凭据进行身份验证时才有效。 */ private boolean tryEncrypt() { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(KEY_NAME, null); Cipher cipher = Cipher.getInstance( KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7); // Try encrypting something, it will only work if the user authenticated within // the last AUTHENTICATION_DURATION_SECONDS seconds. cipher.init(Cipher.ENCRYPT_MODE, secretKey); cipher.doFinal(SECRET_BYTE_ARRAY); // If the user has recently authenticated, you will reach here. showAlreadyAuthenticated(); return true; } catch (UserNotAuthenticatedException e) { // User is not authenticated, let's authenticate with device credentials. showAuthenticationScreen(); return false; } catch (KeyPermanentlyInvalidatedException e) { // This happens if the lock screen has been disabled or reset after the key was // generated after the key was generated. Toast.makeText(this, "密钥在创建后失效,\n" + e.getMessage(), Toast.LENGTH_LONG).show(); return false; } catch (BadPaddingException | IllegalBlockSizeException | KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException(e); } } /** * 在Android密钥存储区中创建对称密钥,该密钥只能在用户具有 *在最近X秒钟内使用设备凭据进行身份验证。 */ private void createKey() { // Generate a key to decrypt payment credentials, tokens, etc. // This will most likely be a registration step for the user when they are setting up your app. try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); KeyGenerator keyGenerator = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); // Set the alias of the entry in Android KeyStore where the key will appear // and the constrains (purposes) in the constructor of the Builder keyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setUserAuthenticationRequired(true) // Require that the user has unlocked in the last 30 seconds .setUserAuthenticationValidityDurationSeconds(AUTHENTICATION_DURATION_SECONDS) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .build()); keyGenerator.generateKey(); } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException | KeyStoreException | CertificateException | IOException e) { throw new RuntimeException("Failed to create a symmetric key", e); } } private void showAuthenticationScreen() { // Create the Confirm Credentials screen. You can customize the title and description. Or // we will provide a generic one for you if you leave it null Intent intent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null); if (intent != null) { startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) { // Challenge completed, proceed with using cipher if (resultCode == RESULT_OK) { if (tryEncrypt()) { showPurchaseConfirmation(); } } else { // The user canceled or didn’t complete the lock screen // operation. Go to error/cancellation flow. Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show(); } } } private void showPurchaseConfirmation() { findViewById(R.id.confirmation_message).setVisibility(View.VISIBLE); findViewById(R.id.purchase_button).setEnabled(false); } private void showAlreadyAuthenticated() { TextView textView = (TextView) findViewById( R.id.already_has_valid_device_credential_message); textView.setVisibility(View.VISIBLE); findViewById(R.id.purchase_button).setEnabled(false); }}
这是xml代码
<?xml version="1.0" encoding="utf-8"?>
更多相关文章
- android用户界面之按钮(Button)教程实例汇
- android ndk编译x264开源(用于android的ffmpeg中进行软编码)
- Android之应用程序基础
- Android使用Retrofit进行网络请求
- haproxy根据客户端浏览器进行跳转
- android用户界面-组件Widget-地图视图MapView
- android用户界面-组件Widget-画廊视图Gallery
- Android(安卓)View的介绍和使用
- Android(安卓)中文 API (27) —— SeekBar.OnSeekBarChangeListene