Enviar senhas de uso único no WhatsApp usando PHP, Laravel e a API da Twilio

March 04, 2020
Escrito por
Brian Iyoha
Contribuidor
As opiniões expressas pelos colaboradores da Twilio são de sua autoria

Enviar senhas de uso único no WhatsApp usando PHP, Laravel e a API da Twilio para WhatsApp

O WhatsApp é frequentemente mencionado como o app de mensagens mais popular do mundo, que permite a comunicação de seus usuários de forma segura e em tempo real. Como proprietário de uma empresa, você pode se basear na velocidade e segurança fornecidas pelo WhatsApp para interagir, enviar alertas e notificações, prestar suporte ou até mesmo enviar OTPs (One-time Passwords, senhas de uso único) aos seus clientes.

Neste tutorial, você aprenderá a enviar notificações com OTPs para os usuários pelo WhatsApp usando a API da Twilio para WhatsApp durante o registro

Pré-requisitos

Para acompanhar este tutorial, você precisará do seguinte:

Configuração do projeto

Este tutorial usará o Laravel, então a primeira etapa é gerar um novo aplicativo Laravel. Usando o Instalador do Laravel, execute o código a seguir no terminal para gerar um novo projeto:

$ laravel new whatsapp-otp

Em seguida, você precisará configurar um banco de dados para o aplicativo. Neste tutorial, usaremos um banco de dados MySQL. Caso não tenha o MySQL na máquina local, acesse o site oficial para saber como instalá-lo. Assim que concluir a instalação com sucesso, acione o terminal e execute este comando para fazer login no MySQL:

$ mysql -u {your_user_name}

OBSERVAÇÃO: adicione o sinalizador -p caso você tenha uma senha para a instância do MySQL.

Depois de fazer login, execute o seguinte comando para criar um banco de dados:

mysql> create database whatsapp-otp;
mysql> exit;

Em seguida, atualize o arquivo .env com suas credenciais do banco de dados. Abra o arquivo .env e faça os ajustes a seguir:

DB_DATABASE=whatsapp-otp
DB_USERNAME={your_user_name}
DB_PASSWORD={your_db_password}

Configurar a API da Twilio para WhatsApp

Para utilizar a API da Twilio para WhatsApp, é necessário obter um número de telefone da Twilio aprovado para WhatsApp, que será utilizado para envio e recebimento de mensagens. Entretanto, isso somente será um pré-requisito se você utilizar a API na produção. Para fins de teste e desenvolvimento, a Twilio disponibiliza a área sandbox, que pode ser usada para envio e recebimento de mensagens pelo WhatsApp em um ambiente de desenvolvedor.

Acessar a sandbox do WhatsApp

Antes de iniciar o teste com a sandbox da Twilio, é necessário participar. Para isso, acesse a seção WhatsApp em seu dashboard da Twilio e envie o texto fornecido (que está no formato join-{unique text}) ao número de WhatsApp disponibilizado. Geralmente é +1 (415) 523-8886.

Dashboard da Twilio para WhatsApp

Ao enviar a mensagem com sucesso, você obterá uma resposta semelhante a esta:

Mensagem do WhatsApp

Agora que você se conectou à sandbox do WhatsApp, é necessário adicionar suas credenciais da Twilio ao arquivo .env da seguinte maneira:

TWILIO_WHATSAPP_NUMBER=
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=

OBSERVAÇÃO: é possível localizar seu número do WhatsApp da Twilio na sandbox, em Sandbox Participants (Participantes da sandbox). O Account SID (SID da conta) e o Auth Token (token de autenticação) estão disponíveis no dashboard.

Enviar OTPs pelo WhatsApp

Para agilizar este tutorial, o suporte de Autenticação do Laravel será usado para autenticar usuários no aplicativo. Acione um terminal no diretório de projetos e execute o seguinte comando para instalar o pacote laravel/ui e também oferecer suporte a um sistema de autenticação básico:

$ composer require laravel/ui --dev
$ php artisan ui bootstrap --auth
$ npm install && npm run dev

Após executá-lo com sucesso, você poderá visualizar o loginregistro, e início, bem como as rotas para autenticação.

OBSERVAÇÃO: para usar o comando npm, é necessário ter o Node.js instalado globalmente em sua máquina.

Em seguida, você precisa criar uma coluna na tabela users (usuários) para armazenar a OTP gerada. Abra o arquivo de migração de usuário (database/migrations/2014_10_12_000000_create_users_table.php) e faça as seguintes alterações no método up():

/**
 * Run the migrations.
 *
 * @return void
 */
public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password');
        $table->string('phone_number');
        $table->string('otp')->nullable();
        $table->rememberToken();
        $table->timestamps();
    });
}

Isso adiciona as colunas otp e phone_number na tabela users, que será usada para armazenar as OTPs e números de telefone dos usuários, respectivamente.

Em seguida, abra o arquivo modelo do User (app/User.php) para adicionar os campos otp e phone_number à matriz fillable:

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = [
    'name', 'email', 'password', 'otp', 'phone_number',
];

Agora, para que esse esquema reflita em seu banco de dados, execute o seguinte comando para processar as migrações disponíveis:

$ php artisan migrate

Modifique a lógica de registro

O suporte básico de autenticação Laravel precisa ser modificado para auxiliar na geração de uma OTP no momento do registro e da entrega pela API da Twilio para WhatsApp. Antes de fazer os ajustes na lógica de registro, é necessário instalar o SDK da Twilio, que será usado para o envio das mensagens do WhatsApp. Abra um terminal no diretório de projetos e execute o seguinte comando para instalá-lo pelo Composer:

$ composer require twilio/sdk

Em seguida, abra o controlador de registro (app/Http/Controllers/Auth/RegisterController.php) e faça as seguintes alterações:

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use App\User;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Twilio\Rest\Client;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
     */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
            'phone_number' => ['required', 'numeric'],
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\User
     */
    protected function create(array $data)
    {
        $otp = rand(1000, 9999);
        $user = User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'phone_number' => $data['phone_number'],
            'password' => Hash::make($data['password']),
            'otp' => $otp,
        ]);

        $this->sendWhatsappNotification($otp, $user->phone_number);
        return $user;
    }

    private function sendWhatsappNotification(string $otp, string $recipient)
    {
        $twilio_whatsapp_number = getenv("TWILIO_WHATSAPP_NUMBER");
        $account_sid = getenv("TWILIO_ACCOUNT_SID");
        $auth_token = getenv("TWILIO_AUTH_TOKEN");

        $client = new Client($account_sid, $auth_token);
        $message = "Your registration pin code is $otp";
        return $client->messages->create("whatsapp:$recipient", array('from' => "whatsapp:$twilio_whatsapp_number", 'body' => $message));
    }

}

O método validator() foi modificado para incluir o campo phone_number, enquanto o método create() também foi modificado para gerar uma OTP numérica de quatro dígitos usando o método integrado rand() do PHP:

$otp = rand(1000, 9999);

Então, o usuário é armazenado no banco de dados usando o método Eloquent create(), que retorna o modelo de User salvo. Após isso, a OTP gerada é enviada ao usuário chamando o método sendWhatsappNotification() e transformando a otp e o phone_number do usuário em argumentos.

O SDK da Twilio é inicializado no método sendWhatsappNotification() usando suas credenciais (disponíveis no Dashboard da Twilio), instanciando uma nova classe Client:

$client = new Client($account_sid, $auth_token);

Depois, o modelo de mensagem para envio da OTP estará preparado:

$message = "Your registration pin code is $otp";

OBSERVAÇÃO: é necessário usar um modelo aprovado para o envio de uma mensagem unidirecional usando a API da Twilio para WhatsApp. Clique aqui para saber mais sobre os modelos para WhatsApp. A sandbox do WhatsApp inclui modelos predefinidos, um deles é: Your {{1}} code is {{2}} (Seu código {{1}} é {{2}})

Este é o modelo em uso no momento, no qual {{1}} e {{2}} são espaços reservados para serem substituídos dinamicamente; neste caso, eles são substituídos por registration e $otp respectivamente.

Em seguida, usando a instância do Twilio Client, a mensagem de modelo é enviada ao destinatário:

$client->messages->create("whatsapp:$recipient", array('from' => "whatsapp:$twilio_whatsapp_number", 'body' => $message));

O método messages→create() aceita dois argumentos de um destinatário da mensagem e uma matriz com as propriedades de from e body, sendo que from é o seu número de telefone da Twilio aprovado para WhatsApp e body é a mensagem que será enviada ao destinatário.

OBSERVAÇÃO: para o dizer ao SDK da Twilio que envie essa mensagem pelo WhatsApp, você deve prefixar o whatsapp: ao número de telefone do destinatário e, também, ao número do WhatsApp da Twilio. Caso não esteja prefixado, a mensagem será enviada como um SMS comum ao destinatário.

Atualizar a visualização

Neste ponto, você já deve ter modificado com sucesso a lógica de registro com suporte para também enviar a OTP aos seus usuários pelo WhatsApp. Agora, você precisa atualizar a visualização para incluir o campo phone_number ao formulário de registro. Abra resources/views/auth/register.blade.php e faça as seguintes alterações no código:

@extends('layouts.app')
  
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('register') }}">
                        @csrf

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror"
                                    name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>

                                @error('name')
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $message }}</strong>
                                </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email"
                                class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control @error('email') is-invalid @enderror"
                                    name="email" value="{{ old('email') }}" required autocomplete="email">

                                @error('email')
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $message }}</strong>
                                </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password"
                                class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>

                            <div class="col-md-6">
                                <input id="password" type="password"
                                    class="form-control @error('password') is-invalid @enderror" name="password"
                                    required autocomplete="new-password">

                                @error('password')
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $message }}</strong>
                                </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="password-confirm"
                                class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control"
                                    name="password_confirmation" required autocomplete="new-password">
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="password"
                                class="col-md-4 col-form-label text-md-right">{{ __('Phone Number') }}</label>

                            <div class="col-md-6">
                                <input id="phone_number" type="tel"
                                    class="form-control @error('phone_number') is-invalid @enderror" value="{{old('phone_number')}}" name="phone_number"
                                    required>

                                @error('phone_number')
                                <span class="invalid-feedback" role="alert">
                                    <strong>{{ $message }}</strong>
                                </span>
                                @enderror
                            </div>
                        </div>


                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Send OTP') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Testar

Para testar seu aplicativo, abra um terminal e execute o seguinte comando:

  $ php artisan serve

Ao fazê-lo com sucesso, você verá sua porta e URL localhost, pela qual é possível acessar o aplicativo Laravel. Ela geralmente é 127.0.0.1:8000. Em seguida, navegue até a página de registro e preencha o formulário. Após isso, clique no botão Send OTP (Enviar OTP) para receber uma breve mensagem do WhatsApp com sua OTP.

Conclusão

Agora que concluiu este tutorial, você aprendeu com sucesso a enviar notificações do WhatsApp pelo seu aplicativo Laravel e também viu como modificar a lógica de registro de autenticação com suporte do Laravel. Se você quiser dar uma olhada no código-fonte completo deste tutorial, ele está disponível no Github.

Você pode ir além e modificar o processo de autenticação para verificar a OTP enviada ao seu usuário antes de conceder a ele acesso ao aplicativo. Também é possível obter mais informações sobre como proteger seu aplicativo Laravel usando o Twilio Authy aqui.

Adoraria esclarecer as suas dúvidas sobre este tutorial. Entre em contato comigo via:

Este artigo foi traduzido do original "Sending One-time Passwords in WhatsApp using PHP, Laravel, and the Twilio API for WhatsApp". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.