Автоматически сгенерированные пароли в iOS 12

    Если в вашем приложении есть функция регистрации, включающая в себя возможность или необходимость ввода новых имени пользователя и пароля, скорее всего, вас заинтересует нововведение в «iOS 12», которое я хотел бы обрисовать. Это сервис, который придумывает новые пароли для пользователя, автоматически подставляет их в нужные поля и безопасно хранит в «Keychain».

    Автоматически-сгенерированные системой пароли являются наиболее стойкими к подбору (будучи случайно-сгенерированными последовательностями символов – с поправкой на настраиваемые ограничения, но об этом позже), избавляют пользователей приложения от необходимости придумывать последовательность самостоятельно и гибко настраиваются под нужды конкретного приложения. Поддержка новой функциональности довольно легко обеспечивается, тем не менее не без особенностей. Но обо всем по порядку.

    Права и обязанности


    В первую очередь, приложение должно заявить о своем желании пользоваться этим функционалом. В список «Capabilities» соответствующего «Target» необходимо иметь, во-первых, домен в списке «Associated Domains». Как ни странно, приложение должно иметь «Associated Domain», чтобы иметь возможность пользоваться сгенерированными паролями и хранить их в «Keychain» пользователя (две эти функции взаимосвязаны, и генерация не может быть использована отдельно от хранения).

    Если приложение уже поддерживает использование общих учетных записей с вашим сайтом (т.н. «Shared Credentials»), то этот шаг уже позади. Также он может быть уже позади, и если приложение поддерживает «Universal Links» или другой механизм обработки внешних «URL»-ссылок.

    Так или иначе, после добавления этой совместимости у приложения появится новое «Entitlement».

    Помимо этой, более общей, совместимости приложение также должно иметь «Capatibility» «AutoFill Credential Provider» – это дает возможность приложению, при наличии разрешения от пользователя, пользоваться предложенными системой логинами и паролями. Добавление этой совместимости повлечет появление разрешения «AutoFill Credential Provider Entitlement».
    К слову, добавление этой и других возможностей доступно только членам «Apple Developer Program».
    В используемый приложением «Provisioning Profile» также должны быть включены перечисленные две функции.

    Используемые зависимости


    Добавление соответствующих совместимостей повлечет за собой появление фреймворка «AuthenticationServices» в списке «Linked Frameworks and Libraries» соответствующего «таргета». Этот момент обладает некоторыми особенностями, которые стоит упомянуть.

    Во-первых, автоматическое добавление связанного фреймворка может не «сработать» с первого раза: при запуске приложения на реальном устройстве из моего экземпляра «Xcode» версии 10.1, приложение сразу «падало» ввиду отсутствия «AuthenticationServices». Ручное удаление фреймворка и добавление его обратно в список связанных компонентов решило проблему.

    Во-вторых, автоматическое добавление фреймворка помечает его как «Required». Если ваше приложение подразумевает возможность работы «под» «iOS» версий ниже 12, это также вызовет его падение на этапе запуска «из-под» операционных систем более низких версий. «AuthenticationServices» доступны только для систем версий от 12-ой. Эта проблема решается отмечанием фреймворка как «Optional».

    Поддержка в текстовых полях


    Для поддержки функционала текстовыми полями используется переменная textContentType протокола UITextInputTraits. Класс UITextField, который, скорее всего, используется для ввода логина и пароля в приложении, уже реализует требования нужного нам протокола.

    textContentType – это поле типа UITextContentType, содержащего лишь набор констант. Нужная нам в данный момент – newPassword, используемая для ввода нового, придумываемого в данный момент, пароля (не путать с просто password, используемой для ввода уже существующего пароля).

    let passwordTextField = UITextField()
    
    if #available(iOS 12, *) {
        passwordTextField.textContentType = .newPassword
    }

    Установка значения textContentType обернуто в проверку доступности «API», потому что, как и общий функционал, эта константа доступна только начиная с «iOS 12».

    Помимо типа содержимого, текстовое поле обязательно должно обеспечивать безопасный ввод данных:

    passwordTextField.isSecureTextEntry = true

    Хотя приложение вполне может обеспечивать популярный в наше время функционал отображения и скрытия введенного пароля, сгенерированный пароль будет предложен, только если в этот момент флаг имеет значение true.

    С типом содержимого текстового поля связан интересный момент: если на экране не будет присутствовать другое поле, с типом содержимого username, автоматически-сгенерированный пароль предложен не будет. Это связано с тем, что функционал основан не просто на указанном типе контента текстоваого поля, а на эвристическом анализе содержимого экрана.

    Кажется, генерация пароля «ломает» логику экранов, которые требуют ввести для проверки новый пароль дважды. По-крайней мере, я пока не нашел способ использовать эти две функциональности совместно. И, похоже, я такой не один.

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

    let userNameTextField = UITextField()
    userNameTextField.keyboardType = .emailAddress
    userNameTextField.textContentType = .username

    Требования к паролям


    Часто пользовательские пароли должны соответствовать некоторым правилам (иметь определенную длину, включать в себя определенные символы и т.д.). Эти правила можно указать для того, чтобы система учитывала их при генерации паролей. Это делается через свойство passwordRules протокола UITextInputTraits. Например:

    if #available(iOS 12, *) {
        passwordTextField.passwordRules = UITextInputPasswordRules(descriptor: "required: upper; required: lower; required: digit; minlength: 8;")
    }

    Свойство также доступно только начиная с «iOS 12».

    Тип свойства – UITextInputPasswordRules. Инициализация – с помощью строки-дескриптора. Дескриптор имеет несложный синтаксис и состоит из простых требований к паролю, перечисленных через точку с запятой. Каждое требование – это пара «ключ-значение», разделенные двоеточием. Ключ представляет собой тип правила (например, «обязательно включает» – required), а значение – элемент, который должен следовать этому правилу (например, цифры – digit).

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

    • required: upper – необходимо присутствие хотя бы одной прописной буквы;
    • required: lower – то же для хотя бы одной строчной буквы;
    • required: digit – то же для хотя бы одной строчной цифры;
    • minlength: 8 – минимальная длина – восемь символов.

    Подробное перечисление возможных ключей и значений можно найти в неплохой статье, опубликованной на сайте «NSHipster».

    А «Apple» предлагает довольно удобного помощника по составлению дескрипторов, который предоставляет не только удобный способ их конструирования, но и проверку составленных дескрипторов в виде неограниченного количества сгенерированных примеров. Там же можно посмотреть, какие правила применяются по-умолчанию.

    Валидация


    На всякий случай следует уточнить, что механизм генерации паролей не обеспечивает валидацию введенных пользователем данных – об этом необходимо позаботиться самостоятельно. Что, конечно, вполне логично, т.к. пользователь приложения может отказаться от предложенного автоматически-сгенерированного пароля или даже запретить генерацию паролей и автозаполнение полей.

    Interface Builder


    Что примечательно и в духе нашего времени, все перечисленные настройки текстовых полей можно выставить в «Interface Builder», вплоть до «Password Rule»:

    image

    Проверка функциональности


    Функционал не сложный, но обладает рядом нюансов: при его настройке легко можно что-нибудь забыть. В этом случае в «debug»-сборках при активации соответствующего текстового поля в консоль будет выведена причина, по которой функциональность в данный момент не действует.

    Например:

    [AutoFill] Cannot show Automatic Strong Passwords for app bundleID: <...> due to error: Cannot save passwords for this app. Make sure you have set up Associated Domains for your app and AutoFill Passwords is enabled in Settings

    Также всегда следует иметь в виду, что данный вид функциональности входит в число действий, на которые требуется разрешение пользователя. В данном случае требуется целых два:

    1. iCloud Keychain;
    2. AutoFill.

    Заключение


    Кажется это все, на что следует обратить внимание во время обеспечения поддержки нового функционала. Если кто-то в процессе работы над этим столкнулся с другими интересными особенностями, буду раз комментариям и, при необходимости, обязательно дополню статью.

    Особенность довольно интересная и при правильном ее использовании вполне способна улучшить пользовательский опыт вашего приложения!
    Поделиться публикацией

    Комментарии 0

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

    Самое читаемое