В этом посте мы рассмотрим интеграцию Face ID в приложение React Native, создание пары ключей RSA 2048, создание подписи RSA-SHA256 и создание сервера NodeJS для проверки подписи Face ID и открытого ключа.
Face ID стал широко используемой функцией безопасности в приложениях для iOS и Android. Эта функция позволяет пользователям испытать простой и безопасный процесс аутентификации при использовании вашего приложения.
Мы будем интегрировать аутентификацию Face ID в приложение React Native, используя пакет react-native-biometrics.
Предпосылки
Чтобы следить за постом, вам понадобится приложение React Native, которое можно легко создать с помощью этой команды:
npx react-native init RealApp

В этом примере мы будем использовать один из предварительно встроенных экранов входа WithFrame с действием Face ID.
Монтаж
Если вы используете пряжу, выполните следующую команду:
yarn add react-native-biometrics
Если вы используете NPM, выполните следующую команду:
npm install react-native-biometrics --save
Также не забываем про линковку нативных пакетов:
npx pod-install
В React Native 0.60+ функция автоссылки CLI связывает модуль при создании приложения.
Разрешения
После завершения установки нам нужно будет добавить строки разрешений для iOS и Android.
Для Android вам нужно будет добавить в файл AndroidManifest.xml следующее:
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
Для iOS вам нужно будет добавить в файл Info.plist следующее:
<key>NSFaceIDUsageDescription</key> <string>Enabling Face ID allows you quick access to RealApp</string>
Шаг 1. Создайте пару биометрических ключей.
На экране входа в систему у нас есть две кнопки: «Войти» и «Face ID». После проверки учетных данных пользователя мы спросим его, не хотят ли они использовать функцию Face ID в следующий раз.
Конечно, сначала нам нужно будет проверить, доступен ли Face ID на устройстве, используя метод isSensorAvailable().
Как только publicKey получен методом createKeys(), мы должны отправить его на сервер и сохранить в сущности пользователя. Позже мы воспользуемся им для проверки подписи.
import ReactNativeBiometrics, { BiometryTypes } from 'react-native-biometrics';
<TouchableOpacity
onPress={async () => {
// Verify user credentials before asking them to enable Face ID
const {userId} = await verifyUserCredentials();
const rnBiometrics = new ReactNativeBiometrics();
const { available, biometryType } =
await rnBiometrics.isSensorAvailable();
if (available && biometryType === BiometryTypes.FaceID) {
Alert.alert(
'Face ID',
'Would you like to enable Face ID authentication for the next time?',
[
{
text: 'Yes please',
onPress: async () => {
const { publicKey } = await rnBiometrics.createKeys();
// `publicKey` has to be saved on the user's entity in the database
await sendPublicKeyToServer({ userId, publicKey });
// save `userId` in the local storage to use it during Face ID authentication
await AsyncStorage.setItem('userId', userId);
},
},
{ text: 'Cancel', style: 'cancel' },
],
);
}
}}>
<View style={styles.btn}>
<Text style={styles.btnText}>Sign in</Text>
</View>
</TouchableOpacity>
Шаг 2. Подтвердите биометрическую подпись
Теперь, когда у нас есть publicKey, хранящийся в сущности пользователя, мы можем использовать его для проверки аутентификации пользователя.
<TouchableOpacity
onPress={async () => {
const rnBiometrics = new ReactNativeBiometrics();
const { available, biometryType } =
await rnBiometrics.isSensorAvailable();
if (!available || biometryType !== BiometryTypes.FaceID) {
Alert.alert(
'Oops!',
'Face ID is not available on this device.',
);
return;
}
const userId = await AsyncStorage.getItem('userId');
if (!userId) {
Alert.alert(
'Oops!',
'You have to sign in using your credentials first to enable Face ID.',
);
return;
}
const timestamp = Math.round(
new Date().getTime() / 1000,
).toString();
const payload = `${userId}__${timestamp}`;
const { success, signature } = await rnBiometrics.createSignature(
{
promptMessage: 'Sign in',
payload,
},
);
if (!success) {
Alert.alert(
'Oops!',
'Something went wrong during authentication with Face ID. Please try again.',
);
return;
}
const { status, message } = await verifySignatureWithServer({
signature,
payload,
});
if (status !== 'success') {
Alert.alert('Oops!', message);
return;
}
Alert.alert('Success!', 'You are successfully authenticated!');
}}>
<View style={styles.btnSecondary}>
<MaterialCommunityIcons
color="#000"
name="face-recognition"
size={22}
style={{ marginRight: 12 }}
/>
<Text style={styles.btnSecondaryText}>Face ID</Text>
<View style={{ width: 34 }} />
</View>
</TouchableOpacity>
Шаг 3: Проверка подписи с помощью открытого ключа в NodeJS
После того, как пользователю будет предложено пройти аутентификацию Face ID, Apple извлечет закрытый ключ из хранилища ключей, а затем использует его для создания подписи RSA PKCS#1v1.5 SHA 256.
Ранее мы сохранили открытый ключ на объекте пользователя, и теперь мы можем использовать его для проверки того, что подпись была подписана с использованием закрытого ключа из той же пары открытый/закрытый ключ. В NodeJS это можно сделать с помощью модуля crypto.
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const app = express();
app.use(bodyParser.json({ type: 'application/json' }));
app.post('/', async (req, res) => {
const { signature, payload } = req.body;
const userId = payload.split('__')[0];
const user = await getUserFromDatabaseByUserId(userId);
if (!user) {
throw new Error('Something went wrong during your Face ID authentication.');
}
// this is the public key that was saved earlier
const { publicKey } = user;
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(payload);
const isVerified = verifier.verify(
`-----BEGIN PUBLIC KEY-----\n${publicKey}\n-----END PUBLIC KEY-----`,
signature,
'base64',
);
if (!isVerified) {
return res.status(400).json({
status: 'failed',
message: 'Unfortunetely we could not verify your Face ID authentication',
});
}
return res.status(200).json({
status: 'success',
});
});
Мы надеемся, что вам понравился этот пост, и теперь вы лучше понимаете, как интегрировать Face ID в ваше приложение React Native.
Окончательный код приложения React Native можно найти в нашем репозитории GitHub.
Этот экран входа и многие другие можно найти на нашем сайте: WithFrame React Native Components