Авторизация по биометрии — Kotlin

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Log.d("Kotlin", "Авторизация по биометрии")

Hi ;-)

Поскольку это моя первая статья на ресурсе, то хотелось бы вообще изначально познакомиться. Возможно, вам это будет неинтересно сейчас читать, поэтому можете спокойно пролистать ниже, где уже будет разбор этой темы. Вся статья будет написана в таком свободном стиле, чтобы не нагружать вас какой-либо терминологией и скукотой, поэтому тут спокойно могут быть ответвление (вдруг анекдот захотелось рассказать), но в общем и целом — не суть. Постараюсь как можно более кратко и понятно все описать, а если будут вопросы, то смело можете писать их тут ниже. Ну... Let's Go.

Кто ты такой?

Я молодой такой разработчик с 2-х летним not official стажем разработки в разных областях, начиная от чистого C, заканчивая видеоигровой (Unity) и мобильной (Flutter, Kotlin) разработкой. Жизнь немного помотала, поэтому и рассматриваю несколько профилей.

На моей практике было не так уж и много (но лично для меня) достойных проектов: сервис по доставке еды «Food in Flight», 1.5-часовая сюжетная около-RPG игра «Game Of Pulpits» и мини-игра в угадай слово, по типу вордли (бесила реклама, вот и решил что-то своё бесплатное сделать).

Если вдруг каким-то образом мои проекты вас заинтересовали, то можете смело зайти на мою страничку на сайте и посмотреть некоторые разработанные проекты (все они некоммерческие, и исходный код располагается на гитхабе). Возможно, в будущем мы рассмотрим некоторые механики из них прямо здесь.

Почему я решил писать статьи? Мне стало интересно смотреть на какие-то интересные механики и реализовывать их, ну а также рассказывать про них. Поэтому если вдруг обнаружите что-то интересное, то пишите, и разберём это тут)

Ну, вроде и так много мыла, поэтому стартуем.

Постановка задачи

Возможно, вы знаете, что есть такая штука, как «менеджер паролей», где хранятся абсолютно все ваши логины, пароли и сайты, к которым они прикреплены. Удобная штука, чтобы не запоминать пароли и уж тем более не писать их вручную. Кому такое надо common. Поэтому многие и пользуются такими штуками по типу KeePass. А теперь смоделируем ситуацию:

Вы решили сходить в магазин и купить какой‑нибудь чешский нефильтрованный напиток, посмотрели на время и увидели, что сейчас 21:45, и совсем скоро магазины закроются. Поэтому вам пришла гениальная идея — побежать, пока магазин не закрылся, но по пути вы уронили телефон и даже этого не заметили. Когда вы возвращались домой с напитком, вы обнаружили, что вашего телефона нет, а каким‑то чудом вы пообещали себе 2 дня назад, что поставите пароль на телефон «на следующий день», что, конечно же, не сделали. Через пару минут вы заходите через ноутбук или компьютер, нажимаете на кнопку «выйти со всех устройств» и думаете, что всё — никаких проблем не будет, но тут вы заходите в вашу любимую социальную сеть и видите, что вашим друзьям или коллегам было отправлено сообщение о займе 1000 рублей. В этот момент вы понимаете, что у вас был включен тот самый менеджер паролей, в который мог зайти абсолютно любой, получив ваш телефон в руки.

И вот мы подобрались к сути проблемы: нам нужно защитить этот самый менеджер паролей пользователя от людей, кому вход туда категорически запрещен.

Вы подумаете, что реализуете вход по логину и паролю и всё: защита есть, но скорее всего, тогда вашим менеджером никто не будет пользоваться, потому что будет просто неудобно. А как сделать так, чтобы пользователю хотелось им пользоваться уже на стадии входа в этот самый менеджер? Всё просто: вход по биометрии.

Подготовка нашего проекта

Для нашего такого простенького проекта мы должны добавить одну зависимость и установить одно разрешение.

Зависимость: biometric
Разрешение: запись данных

Как установить зависимость?
Заходим в файл build.gradle, который располагается в проекте, например, так: NameApp/app/build.gradle и внизу в блок "dependency" (зависимость) вставляем вот эту строку:

implementation 'androidx.biometric:biometric:1.1.0'

1.1.0 — последняя версия на 17.07.2023 устанавливаемого пакета, если вдруг выйдет новая, то её можно посмотреть вот тут: *клик*

Как установить разрешение?
Заходим в файл AndroidManifest.xml, который располагается в проекте, например, так: NameApp/app/src/main/AndroidManifest.xml и перед блоком <application ... /> вставляем эту строку:

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

Всё. Поздравляю, теперь можем начинать. Два файла — две строки, и мы уже можем создавать наш вход по биометрии! Magic.

Создание входа по биометрии

Рисунок 1 — Основные экраны
Рисунок 1 — Основные экраны

На рисунке 1 продемонстрированы 3 основных экрана: регистрация, авторизация и ваше основное окошко.

Мы не будем подробно разбирать прямо сейчас реализацию механик «ввод пароля», «проверка пароля» и тому подобного. Мы разберём одну лишь кнопку «Log in using the biometric»

Создадим в нашем активити две приватные переменные:

  private var isHaveBiometric: Boolean = true
  private lateinit var biometricPrompt: BiometricPrompt

isHaveBiometric — булевая переменная, которая будет отвечать у нас за то, есть ли у пользователя на устройстве поддержка биометрии
biometricPrompt — объект, который представляет собой диалоговое окно системной аутентификации по биометрии

Возможны, вы спросите: «А зачем нам нужна эта булевая переменная isHaveBiometric?». Ответ прост: не у всех пользователей есть эта самая система авторизации по биометрии, поэтому было бы странно, что пользователь будет видеть кнопку «Вход по биометрии», когда его устройство это не поддерживает. Поэтому создадим метод checkBiometricInDevice и вызовем его при запуске текущего экрана.

private fun checkBiometricInDevice() {
        val biometricManager = BiometricManager.from(this)
        val buttonOpenBiometric = findViewById<Button>(R.id.buttonOpenCamera)

        when (biometricManager.canAuthenticate()) {
            BiometricManager.BIOMETRIC_SUCCESS -> {
                buttonOpenBiometric.visibility = View.VISIBLE
                isHaveBiometric = true
            }

            else -> {
                buttonOpenBiometric.visibility = View.GONE
                isHaveBiometric = false
            }
        }
    }

2 строка — создадим объект, который будем использовать для проверки возможности аутентификации пользователя с помощью биометрии.
3 строка — наша кнопка, при нажатии на которую пользователь сможет войти с помощью биометрии.
5-15 строки — в зависимости от результата проверки он устанавливает видимость кнопки и значение булевой переменной.

Поздравляю, половина дела сделана. Да-да, всё настолько просто. Уже полпути позади.

Теперь сделаем так, чтобы при нажатии на кнопку «Вход по биометрии» появлялось окно авторизации. Для этого создадим метод initializeButtonForBiometric()

private fun initializeButtonForBiometric() {
       val buttonBiometric = findViewById<Button>(R.id.buttonOpenBiometric)

        biometricPrompt = BiometricPrompt(this@MainActivity, ContextCompat.getMainExecutor(this), object:androidx.biometric.BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                val cryptoObject = result.cryptoObject
                SetActivity(SecondActivity::class.java, true)
            }

            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                Toast.makeText(this@MainActivity, "Error", Toast.LENGTH_SHORT).show()
            }

            override fun onAuthenticationFailed() {
                Toast.makeText(this@MainActivity, "Error", Toast.LENGTH_SHORT).show()
            }
        }
        )

        buttonBiometric.setOnClickListener {
            biometricPrompt.authenticate(createBiometricPromptInfo())
        }
    }

2 строка — наша кнопка, при нажатии на которую вся эта штука сработает
4 строка — создание объекта, где в конструктор передаются ссылка на текущую активность, исполнитель ContextCompat.getMainExecutor(this) и анонимный объект AuthenticationCallback.

Нам необходимо переопределить 3 метода:

  1. onAuthenticationSucceeded — для успешного входа;

  2. onAuthenticationError — для обработки ошибки при входе по биометрии (например, когда несколько раз не считывается отпечаток пальца);

  3. onAuthenticationFailed — для обработки ошибки, когда вход по биометрии не удался.

Для 2 и 3 метода вы можете прописать такую логику, которую захотите. Я написал просто вывод одного сообщения «Error». Креативно? А то.

Для 1 метода идёт реализация логики при успешном вводе биометрических данных, в нашем случае — переход к следующему экрану.

На 20-22 строках реализована обработка нажатия по кнопке «вход», где будет открываться как раз наше окно. Дополнительно я создал метод createBiometricPromptInfo. Вот код этой самой функции:

private fun createBiometricPromptInfo(): PromptInfo {
        return PromptInfo.Builder()
            .setTitle("Authorization")
            .setNegativeButtonText("Cancel")
            .build()
    }

Надеюсь, тут ничего пояснять не надо, поскольку тут типичный инглиш.

  • Название окна — Авторизация (Authorization)

  • Кнопка выхода из авторизации по биометрии — Отмена (Cancel)

Готово. Теперь нужно всё это использовать в нашем методе "OnCreate"

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        checkBiometricInDevice() // Тут проверяем есть ли вход по биометрии у пользователя
        initializeButtons() // Тут инициализированы кнопки "Log in" и "Sign in"

        if (isHaveBiometric) { // Тут проверка 
            initializeButtonForBiometric() // тут инициализируем кнопку входа по биометрии
        }
    }

Вот и все, теперь пользователь может без ввода пароля спокойно зайти в приложение.

Рисунок 2 — Вход
Рисунок 2 — Вход

Всё представленное ниже приложение вы можете найти вот тут: RskullW/AuthenticatorMobile (github.com)

Спасибо, что прочитали. Может быть, для кого-то эта статья стала полезной. Пишите в комментариях механики, которые хотели бы разобрать. И это может быть не только Kotlin, но и C++, Dart/Flutter, C#, Unity.

Всем кчау ;-)

Источник: https://habr.com/ru/articles/748872/


Интересные статьи

Интересные статьи

Привет, Хабр! Я Дмитрий Воронов из Doubletapp, в этой статье расскажу, как мы делали навигацию в Яндекс Путешествиях. С навигацией в Android, кажется, давно все ясно: бери Jetpack Navigation, читай оф...
Первое, в чём может возникнуть затруднение у Android разработчика при переходе на ККМ - это быстрая настройка окружения. Официальный сайт Kotlin не пестрит подробными инструкциями, и можно потратить н...
Вы узнаете, как с помощью модулей Koin ограничивать область живучести зависимостей, относящихся к конкретному компоненту. Вы также познакомитесь со стандартными областями...
Всем привет! Целый месяц мы изучали работы участников конкурса. И честно сказать, получили массу удовольствия в процессе, причём дважды: сначала — читая ваш код и радуясь красивым архитектурн...
Андрей Бреслав (abreslav) известен прежде всего как человек, возглавляющий работу над языком Kotlin. Но в последнее время он стал выступать с докладами совсем о другом: весной говорил о важно...