https://a.storyblok.com/f/270183/1604554/c62c7c99fd/screen-shot-2016-12-03-at-11-50-47-am.png

Como adicionar verificação por telefone e biometria ao seu aplicativo para iOS

Publicado em May 17, 2021

Tempo de leitura: 10 minutos

Autenticação de dois fatores (2FA) adiciona uma camada extra de segurança para usuários que estão acessando informações confidenciais. Existem vários tipos de 2FA, tais como:

  • Algo que você sabe (nome de usuário, senha)

  • Algo que você tem (seu celular/cartão SIM)

  • Algo que você possui (impressão digital biométrica ou varredura da retina)

Neste tutorial, vamos explicar como você pode adicionar esses três recursos a um aplicativo para iOS usando o SDK do Nexmo Verify.

Introdução

O uso do SDK permitirá que você adicione uma camada extra de segurança. Você garantirá que o usuário esteja vinculado a um dispositivo físico específico ao capturar o ID do dispositivo e um código PIN por SMS/TTS. Confirmar que o usuário está fazendo login a partir do mesmo dispositivo da tentativa anterior de login reduz o spam e a fraude.

Usaremos um aplicativo inicial (Swift 3) que utiliza um Back4App para o login do usuário (algo que você sabe). Usaremos o SDK do Verify para nossa solução de autenticação de duas etapas (2FA) via SMS e TTS, e o Touch ID da Apple para verificação biométrica (algo que você é).

Configure seu banco de dados do Back{4}App

O Back{4}App é um backend que permite desenvolver e hospedar aplicativos do Parse (o que é útil, já que o Parse encerrou suas atividades). Se você ainda não tem um Account no Back{4}App, cadastre-se e crie um aplicativo.

Creating a new app in Back{4}App

Depois que seu aplicativo estiver criado, clique no botão “servidor” na seção “Configurações principais”. Você será direcionado para uma página com as credenciais do seu novo aplicativo. Depois de anotar o ID do aplicativo e a chave do cliente, clique no botão “Voltar” e acesse o “Painel”, localizado na seção “Configurações principais”. Ao ser redirecionado para o painel, acesse a seção “Core”, clique em “Editar” (localizado no canto superior direito) e adicione as seguintes colunas à classe “User”:

  • 'verificação' (Número)

  • 'salvando (Número)

  • 'sitekey' (Arquivo - imagem para usuários)

  • phoneNumber (string)

  • ‘smsVerification’ (valor booleano — permite que os usuários ativem a verificação por SMS no login)

Adding a new column to the 'User' class

Agora que o Back{4} Apps está configurado, podemos começar a montar nosso aplicativo inicial.

Baixe o aplicativo Starter

Vamos começar baixando o aplicativo inicial do GitHub. No Terminal, execute o seguinte:

git clone https://github.com/nexmo-community/nexmo-verify-2fa-ios-example.git -b getting-started cd nexmo-verify-2fa-ios-example

O repositório possui um branch “getting-started” (pré-2FA), que permite que você siga o tutorial abaixo, e um branch “master”, que contém a versão final deste tutorial.

Abra o NexmoBankingApp.xcproj no XCode. Selecione “NexmoBankingApp” para abrir as configurações do seu aplicativo e atualize o “Identificador do Pacote” do projeto para um identificador válido e um nome de aplicativo registrado no Portal do Desenvolvedor da Apple. Adicione seu ID de Aplicativo e Chave de Cliente do Back4App em AppDelegate.swift.

let configuration = ParseClientConfiguration {
$0.applicationId = "BACK4APP_APP_ID"
$0.clientKey = "BACK4APP_CLIENT_KEY"
$0.server = "https://parseapi.back4app.com"
}
Parse.initializeWithConfiguration(configuration)

Depois de entrar, vá até o arquivo “ViewController.swift” e adicione um usuário fictício ao banco de dados, removendo o comentário da chamada à função “signUpDemoAccount()” no método “viewDidLoad()” do arquivo “ViewController.swift”:

override func viewDidLoad() {
super.viewDidLoad()
self.onlineID.delegate = self
signUpDemoAccount() //Uncomment to create dummy user
}

Atualize os campos username, password, email e phoneNumber do PFUser na função 'signUpDemoAccount()'.

func signUpDemoAccount() {
var user = PFUser()
user.username = "ENTERUSERNAME"
user.password = "ENTERPASSWORD"
user.email = "ENTEREMAILADDRESS@DEMO.NET"
user["phoneNumber"] = "ENTER-YOUR-PHONE-HERE"
user["smsVerification"] = false
user["checking"] = 5000
user["saving"] = 10000
let sitekeyImage = UIImage(named: "nexmo.png")
let imageData = UIImagePNGRepresentation(sitekeyImage!)
let imageFile = PFFile(name:"nexmo.png", data:imageData!)
user["sitekey"] = imageFile
user.signUpInBackground {
(success, error) -> Void in
if !success {
print(error.debugDescription)
} else {
print("User signed up.")
}
}
}

Execute o aplicativo. O usuário PFUser será criado e aparecerá no painel do Back4App. Para evitar a criação de outro usuário ao reiniciar o aplicativo, você deve comentar a chamada à função 'signUpDemoAccount()' no método 'viewDidLoad()' após executar o aplicativo pela primeira vez.

User is created and stored in Back{4}Apps

Vá em frente e execute o aplicativo novamente. Você poderá acessar as informações do Account do usuário digitando as credenciais do usuário recém-criado.

Tudo bem, agora vamos reforçar a segurança do aplicativo adicionando a autenticação de dois fatores (2FA).

Configurando seu aplicativo Nexmo

Crie um Account na Nexmo e acesse seu painel do cliente. Clique na aba “Verify” e adicione um novo aplicativo na seção “Seus Applications”. Configure seu aplicativo definindo um nome, o tempo de inatividade como “Imediato” (tempo máximo durante o qual o usuário permanecerá verificado; nesse caso, a verificação dos usuários expirará imediatamente) e o comprimento do código PIN.

Add a new Nexmo App in the dashboard

A seguir, vamos adicionar o SDK do Nexmo Verify. O SDK do Verify pode ser facilmente adicionado ao seu projeto usando o Cocoapods. Crie um arquivo Podfile no diretório do seu projeto, adicione o pod “NexmoVerify” ao arquivo e instale o pod pelo Terminal. (Se o pod não for encontrado, execute o comando `pod update` para atualizar o Cocoapods.)

pod init open Podfile
Inside Podfile
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
target 'NexmoBankingApp' do
# Comment this line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for NexmoBankingApp
pod ‘NexmoVerify’
end
pod install

Assim que a instalação do Pod estiver concluída, feche o Xcode e abra o novo arquivo de projeto “xcworkspace”. Agora você está pronto para mergulhar no código!

Se você quiser saber mais sobre o NexmoVerify pod, você pode conferir o código-fonte no Github.

Mergulhando no código

Agora que você já instalou as dependências e obteve as credenciais do aplicativo Nexmo, é hora de adicioná-las ao seu arquivo 'AppDelegate'.

No arquivo AppDelegate.swift:

import NexmoVerify //Add to top of the file

fileprivate var appID = "YOUR_NEXMO_APP_ID"
fileprivate var sharedSecret = "YOUR_NEXMO_SHARED_SECRET"

Inicializar o cliente Nexmo

Inicialize o Nexmo Client dentro da função ‘didFinishLaunchingWithOptions’ do arquivo ‘AppDelegate’.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let configuration = ParseClientConfiguration {
$0.applicationId = "BACK4APP_APP_ID"
$0.clientKey = "BACK4APP_CLIENT_KEY"
$0.server = "https://parseapi.back4app.com"
}
Parse.initializeWithConfiguration(configuration)
NexmoClient.start(applicationId: appID, sharedSecretKey: sharedSecret)
return true
}

Adicionar verificação biométrica ao SitekeyViewController

Após o login bem-sucedido, como fornecemos ao Back4Apps a combinação de nome de usuário e senha, a segunda tela leva o usuário à verificação da chave do site, onde adicionaremos a verificação biométrica por Touch ID.

Vamos lidar com a situação em que o usuário clica no botão de login usando a API LocalAuthentication da Apple para solicitar uma verificação por Touch ID. Se o dispositivo não for compatível com o Touch ID (sem leitor de impressão digital), o usuário pula a verificação biométrica. Adicione um segue (‘signInStopped’) para que, caso o usuário não consiga passar na verificação do Touch ID, ele seja desconectado e redirecionado para a página de login. Com base na configuração de preferência de verificação por SMS do usuário, a função “continuar fluxo de trabalho” acionará uma solicitação de verificação após a transição para a tela de verificação por PIN (que criaremos a seguir) ou exibirá a página da Account do usuário.

import LocalAuthentication

@IBAction func signInButton(_ sender: AnyObject) {
initialWorkFlow()
}
func initialWorkFlow() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Authenticate with Touch ID"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason, reply:
{(success, error) in
if success {
self.continueWorkflow()
}
else {
let alert = UIAlertController(title: "Failed Identification", message: "Touch ID Authentication Failed. Sign In process stopped.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Continue", style: .default) {
UIAlertAction in
PFUser.logOut()
self.performSegue(withIdentifier: "signInStopped", sender: self)
}

alert.addAction(defaultAction)
self.present(alert, animated: true, completion: nil)
}
})
}
else {
print("Touch ID not available")
self.continueWorkflow()
}
}
func continueWorkflow() {
if (PFUser.current()?["smsVerification"] as! Bool) {
self.performSegue(withIdentifier: "verifyPin", sender: self)
}
else {
self.performSegue(withIdentifier: "showAccount", sender: self)
}
}

Touch ID requested

Adicionar um controlador de visualização para verificação e adicionar a lógica de autenticação de duas etapas ao controlador de visualização

Adicione um novo arquivo ao seu projeto (“VerifyPinViewController”) e crie um controlador de visualização no Storyboard usando o Interface Builder. Abra o menu “Utilitários” clicando no botão no canto superior direito do Interface Builder. Clique no botão “Identity Inspector” e digite o nome da nova classe após vincular o controlador de visualização no IB ao arquivo. Em seguida, adicione uma caixa de texto (“pinCode” – IBOutlet) junto com um botão (“verifyPin” – IBAction) para enviar o código PIN. Crie uma transição (“verifyPin”) conectada ao “SitekeyViewController” e ao controlador de visualização recém-criado.

Dentro do método “viewDidAppear” do controlador de visualização recém-adicionado, chame a função abaixo.

import Foundation
import UIKit
import Parse
import NexmoVerify

class VerifyViewController : UIViewController {
@IBOutlet weak var pinCode: UITextField!
@IBAction func verifyButton(_ sender: Any) {
}

override func viewDidLoad() {
super.viewDidLoad()
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
let alert = UIAlertController( title: "User Phone Verification", message: "Your identity is being verified.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Continue", style: .default) {
UIAlertAction in
self.verifyUser()
}
alert.addAction(defaultAction)
present(alert, animated: true, completion: nil)
}

Link Class in IB

Recupere o número de telefone do usuário do banco de dados do Back4Apps e acione uma solicitação de verificação usando o método getVerifiedUser(). Crie uma transição (“pinVerified”) que conecte o “VerifyPinController” ao “StatementViewController”.

func verifyUser() {
VerifyClient.getVerifiedUser(countryCode: "US", phoneNumber: PFUser.current()?["phoneNumber"] as! String,
onVerifyInProgress: {
},
onUserVerified: {
self.performSegue(withIdentifier:"pinVerified", sender: self)
},
onError: { verifyError in
switch (verifyError) {
case .invalidPinCode:
UIAlertView(title: "Wrong Pin Code", message: "The pin code you entered is invalid.", delegate: nil, cancelButtonTitle: "Try again!").show()
case .invalidCodeTooManyTimes:
let alert = UIAlertController(title: "Unsucessful Identification", message: "Logging out. Goodbye.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Goodbye", style: .default) {
UIAlertAction in

VerifyClient.cancelVerification() { error in
if let error = error {
// something wen't wrong whilst attempting to cancel the current verification request
return
}
}
self.performSegue(withIdentifier: "logout", sender: self)
}
alert.addAction(defaultAction)
self.present(alert, animated: true, completion: nil)
default:
print(verifyError.rawValue)
break
}
})
}

Além disso, chame o checkPinCode método fornecido pelo cliente Nexmo quando o botão for pressionado para verificar o PIN fornecido pelo usuário.

@IBAction func verifyButton(sender: AnyObject) {
if pinCode.text!.isEmpty {
let alert = UIAlertController(title: "Enter Pin Code", message: "Please check your phone and enter the pin code send via SMS.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Back", style: .default, handler: nil)
alert.addAction(defaultAction)
present(alert, animated: true, completion: nil)
}
else {
VerifyClient.checkPinCode(pinCode.text!)
}
}

Adicionar opção de verificação por SMS no login

Em seguida, adicione a lógica que permite ao usuário ativar a verificação por SMS. Adicione um elemento de interface do usuário do tipo “switch” ao seu ‘StatementViewController’ como um IBOutlet. Além disso, adicione uma variável booleana para armazenar o valor do botão de alternância. O valor do botão é armazenado no banco de dados quando o usuário se desconecta. Se o botão estiver ativado, uma verificação por SMS será acionada no próximo login. Após a exibição da tela, verifique os valores das contas corrente e poupança para garantir que não sejam nulos.

@IBOutlet weak var switch2FA: UISwitch!
var switchBoolValue:Bool!
func logout() {
if switchBoolValue == true {
let alert = UIAlertController(title: "SMS Verification", message: "Perform SMS verification on login?", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Continue", style: .default) {
UIAlertAction in
PFUser.current()?["smsVerification"] = true
PFUser.current()?.saveInBackground()
self.performSegue(withIdentifier: "logoutUser", sender: self)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(defaultAction)
alert.addAction(cancelAction)
self.present(alert, animated: true, completion: nil)
}
else {
print("SMS FALSE successful logout")
PFUser.current()?["smsVerification"] = false
PFUser.current()?.saveInBackground()
self.performSegue(withIdentifier: "logoutUser", sender: self)
}
}

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
if (PFUser.current()?["saving"] == nil || PFUser.current()?["checking"] == nil) {
PFUser.logOut()
self.performSegue(withIdentifier: "logout", sender: self)
}
else {
switch2FA.addTarget(self, action: #selector(StatementViewController.switchMoved), for: UIControlEvents.valueChanged)
switchBoolValue = true
}
}

func switchMoved() { // stores value for the switch
if switch2FA.isOn {
switchBoolValue = true
print("switch on")
}
else {
switchBoolValue = false
print("switch off")
}
}

User Accounts Summary

Executar a autenticação de dois fatores (2FA) para usuários verificados ao realizar uma ação específica

Verify Pin Screen

Transfer Funds

Para transações mais seguras, como quando um usuário transfere fundos de um Account para outro, é possível acionar uma solicitação de verificação para confirmar a ação solicitada pelo usuário.

Adicione um novo controlador de visualização (“TransferPinViewController”) com um campo de texto (“pinCode” – IBOutlet) e um botão (“verifyButton” – IBAction) no arquivo do storyboard. Crie uma transição (“verifyTransfer”) do “TransferViewController” para o controlador de visualização recém-criado.

As contas correntes, as contas poupança, o valor da transferência, a origem da transferência e o total após a transferência serão enviados com o segue. Atualize as funções de transferência (“checkingToSaving” e “savingToChecking”) para redirecionar o usuário para o “TransferPinViewController” após verificar o saldo disponível para a transferência.

func checkingToSaving() {
print("checkingToSaving")
if checkingAmount - transferAmt > 0 {
print("NEWTOTAL: \(checkingAmount - transferAmt)")
transferSource = "checkingToSaving"
afterTransferTotal = checkingAmount - transferAmt
self.performSegue(withIdentifier: "verifyTransfer", sender: self)
}

else {
print("ERROR")
let alert = UIAlertController(title: "Transfer Error", message: "You do not have the requested transfer amount in your Checking Account. Please try again.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Back", style: .default, handler: nil)
alert.addAction(defaultAction)
self.present(alert, animated: true, completion: nil)

}
}
func savingToChecking() {
if savingAmount - transferAmt > 0 {
transferSource = "savingToChecking"
afterTransferTotal = savingAmount - transferAmt
self.performSegue(withIdentifier: "verifyTransfer", sender: self)
}
else {
print("ERROR")
let alert = UIAlertController(title: "Transfer Error", message: "You do not have the requested transfer amount in your Savings Account. Please try again.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Back", style: .default, handler: nil)
alert.addAction(defaultAction)
self.present(alert, animated: true, completion: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any!) {
if (segue.identifier == "verifyTransfer") {
let verifyTransferVC = segue.destination as! TransferPinViewController;
verifyTransferVC.checkingAmount = checkingAmount
verifyTransferVC.savingAmount = savingAmount
verifyTransferVC.transferAmt = transferAmt
verifyTransferVC.transferSource = transferSource
verifyTransferVC.afterTransferTotal = afterTransferTotal
}
}

Crie uma função que chame o método “getVerifiedUser” para iniciar a verificação do usuário. Essa função deve ser chamada quando a visualização for carregada.

import NexmoVerify //Add to top of the file

override func viewDidLoad() {
super.viewDidLoad()
verify()
}
func verify() {
VerifyClient.getVerifiedUser(countryCode: "US", phoneNumber: PFUser.current()?["phoneNumber"] as! String,
onVerifyInProgress: {
},
onUserVerified: {
self.performTransfer()
},
onError: { verifyError in
switch (verifyError) {
case .invalidPinCode:
UIAlertView(title: "Wrong Pin Code", message: "The pin code you entered is invalid.", delegate: nil, cancelButtonTitle: "Try again!").show()
case .invalidCodeTooManyTimes:
let alert = UIAlertController(title: "Unsucessful Identification", message: "Logging out. Goodbye.", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "Goodbye", style: .default) {
UIAlertAction in
VerifyClient.cancelVerification() { error in
if let error = error {
// something wen't wrong whilst attempting to cancel the current verification request
return
}
}
self.performSegue(withIdentifier: "logout", sender: self)
}
alert.addAction(defaultAction)
self.present(alert, animated: true, completion: nil)
default:
print(verifyError.rawValue)
break
}
})
}

Conforme mostrado acima, chame a função 'performTransfer' dentro do método de callback 'onUserVerified'. Assim como fizemos no controlador de visualização de verificação anterior, chame o método 'checkPinCode' dentro do seu botão IBAction para verificar o PIN fornecido pelo usuário. Por fim, crie uma transição (“sucessfulTransfer”) do “VerifyPinViewController” para o “StatementViewController” para redirecionar o usuário à tela “Statements” após a transferência bem-sucedida.

@IBOutlet weak var pincode: UITextField!
@IBAction func checkPin(sender: AnyObject) {
VerifyClient.checkPinCode(pincode.text!)
}
func performTransfer() {
if transferSource == "checkingToSaving" {
checkingAmount = checkingAmount - transferAmt
savingAmount = savingAmount + transferAmt
PFUser.current()?["checking"] = checkingAmount
PFUser.current()?["saving"] = savingAmount
PFUser.current()?.saveInBackground()
OperationQueue.main.addOperation {
self.performSegue(withIdentifier: "successfulTransfer", sender: self)
}
}
else if transferSource == "savingToChecking"{
savingAmount = savingAmount - transferAmt
checkingAmount = checkingAmount + transferAmt
PFUser.current()?["saving"] = savingAmount
PFUser.current()?.saveInBackground()
PFUser.current()?["checking"] = checkingAmount
PFUser.current()?.saveInBackground()
OperationQueue.main.addOperation {
self.performSegue(withIdentifier: "successfulTransfer", sender: self)
}
}
}

Isso é tudo o que você precisa fazer para ativar a autenticação de dois fatores no seu aplicativo para iOS usando o SDK Verify da Nexmo.

Hoje em dia, habilitar a autenticação de dois fatores (2FA) é essencial para gerenciar o acesso a informações confidenciais e garantir a identificação adequada do usuário. Neste tutorial, protegemos o aplicativo de demonstração com os três métodos de autenticação. Ao usar a combinação de nome de usuário e senha, garantimos algo que o usuário sabe (credenciais de login). Ao implementar o SDK Verify para iOS da Nexmo, garantimos a verificação de algo que o usuário possui (acesso ao celular, por meio da captura do ID do dispositivo e do endereço IP do usuário). A adição do Touch ID da Apple garantiu a verificação de algo que o usuário é (ele mesmo), por meio da verificação biométrica.

O processo de adicionar a autenticação de dois fatores (2FA) é simples quando se utiliza o Verify SDK e a API de autenticação local da Apple, e isso acrescenta uma camada extra de segurança que protege as informações confidenciais dos seus usuários.

Fique à vontade para me enviar suas opiniões ou perguntas no Twitter @sidsharma_27.

Compartilhar:

https://a.storyblok.com/f/270183/150x150/a3d03a85fd/placeholder.svg
Sidharth Sharma