Neste tutorial, veremos como verificar números de telefone usando o Twilio Verify criando um sistema de autenticação simples em Laravel.
O Twilio Verify facilita e torna mais seguro verificar o número de telefone de um usuário em comparação aos sistemas de verificação personalizados. Ele garante que o número de telefone seja válido enviando um código curto via SMS para o número durante o registro. Isso pode ajudar a reduzir o número de contas falsas criadas e as taxas de falha ao enviar notificações por SMS aos usuários.
Pré-requisito
Para seguir este tutorial, você precisará do seguinte:
- Conhecimento básico do Laravel
- Laravel instalado no computador local
- Composer instalado globalmente
- Conta da Twilio
Primeiros passos
Crie um novo projeto Laravel usando Instalador do Laravel. Se não o instalou ou se preferir usar o Composer, você pode verificar como fazer isso na Documentação do Laravel. Execute este comando na janela do console para gerar um novo projeto Laravel:
$ laravel new twilio-phone-verify
Agora, mude o diretório de trabalho para twilio-phone-verify
e instale o SDK da Twilio PHP via composer:
$ cd twilio-phone-verify
$ composer require twilio/sdk
Se o Composer não estiver instalado no computador, siga as instruções disponíveis aqui para instalá-lo.
Você precisará de suas credenciais da Twilio no dashboard da Twilio para concluir a próxima etapa. Acesse o dashboard e anote o account_sid (SID da conta) e o auth_token (token de autenticação).
Navegue até a seção Verify (Verificar) para criar um novo Serviço Twilio Verify. Anote o sid
gerado para você após a criação do serviço Verify, pois ele será usado para autenticar a instância do SDK do Verify.
Atualize o arquivo .env com suas credenciais da Twilio. Abra o.env localizado na raiz do diretório do projeto e adicione estes valores:
TWILIO_SID="INSERT YOUR TWILIO SID HERE"
TWILIO_AUTH_TOKEN="INSERT YOUR TWILIO TOKEN HERE"
TWILIO_VERIFY_SID="INSERT YOUR TWILIO SYNC SERVICE SID"
Como configurar o banco de dados
Este tutorial exigirá um banco de dados MySQL para seu aplicativo. Se você usa um cliente MySQL como phpMyAdmin para gerenciar seus bancos de dados, crie um banco de dados chamado de phone-verify
e ignore esta seção. Caso contrário, instale o MySQL do site oficial para a plataforma de sua escolha. Após a instalação, ative seu terminal e execute este comando para fazer login no MySQL:
$ mysql -u {your_user_name}
OBSERVAÇÃO: adicione o sinalizador -p se você tiver 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 phone-verify;
mysql> exit;
Atualize suas variáveis ambientais com suas credenciais de banco de dados. Abra o arquivo .env
e faça os ajustes a seguir:
DB_DATABASE=phone-verify
DB_USERNAME={your_user_name}
DB_PASSWORD={password if any}
Como atualizar a migração e o modelo do usuário
Agora que seu banco de dados foi configurado, atualize user
migrations (migrações de usuário) para criar as colunas necessárias para seus usuários. Por padrão, o Laravel cria uma migração de usuário e um Model (Modelo) quando um novo projeto é gerado. Somente alguns ajustes serão necessários para atender às necessidades deste tutorial.
Abra a pasta do projeto em seu IDE/editor de texto favorito para começar a atualizar os campos necessários na tabela de users (usuários). Abra o arquivo de migração de users (usuários) (database/migrations/2014_10_12_000000_create_users_table.php
) e faça os seguintes ajustes no método up()
:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('phone_number')->unique();
$table->boolean('isVerified')->default(false);
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
Os campos phone_number e isVerified
foram adicionados para armazenar o número de telefone de um usuário e verificar se o número de telefone foi verificado, respectivamente.
Execute o seguinte comando na raiz do diretório do projeto para adicionar esta tabela ao seu banco de dados:
$ php artisan migrate
Se o arquivo for migrado corretamente, você verá o nome do arquivo({time_stamp}_create_users_table
) impresso na janela do console.
Agora, atualize as propriedades de fillable do modelo User (Usuário) para incluir os campos phone_number
e isVerified
. Abra app/User.php
e faça as seguintes alterações na matriz $fillable
:
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password', 'phone_number', 'isVerified'
];
Implementando a lógica de autenticação
Nesse ponto, você já configurou seu projeto Laravel com o SDK PHP da Twilio e criou seu banco de dados. Em seguida, você escreverá nossa lógica para autenticar um usuário. Primeiro, gere um AuthController
que abrigará toda a lógica necessária para cada etapa de autenticação. Abra uma nova janela de console no diretório raiz do projeto e execute o seguinte comando para gerar um Controller (Controlador):
$ php artisan make:controller AuthController
O comando acima gerará um arquivo de classe de controller (controlador) em app/Http/Controllers/AuthController.php
.
Como registrar usuários
Agora é hora de implementar sua lógica de autenticação. Primeiro, você implementará a lógica de registro. Vamos supor que você enviará notificações por SMS para usuários registrados a partir de seu aplicativo. Você precisará garantir que os números de telefone armazenados em seu banco de dados estejam corretos. Não há lugar melhor para aplicar essa validação do que no ponto de registro. Para isso, você usará o Twilio Verify para verificar se o número de telefone inserido pelo usuário é um número de telefone válido.
Abra app/Http/Controllers/AuthController.php
e adicione o seguinte método:
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(Request $request)
{
$data = $request->validate([
'name' => ['required', 'string', 'max:255'],
'phone_number' => ['required', 'numeric', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
]);
/* Get credentials from .env */
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio_sid = getenv("TWILIO_SID");
$twilio_verify_sid = getenv("TWILIO_VERIFY_SID");
$twilio = new Client($twilio_sid, $token);
$twilio->verify->v2->services($twilio_verify_sid)
->verifications
->create($data['phone_number'], "sms");
User::create([
'name' => $data['name'],
'phone_number' => $data['phone_number'],
'password' => Hash::make($data['password']),
]);
return redirect()->route('verify')->with(['phone_number' => $data['phone_number']]);
}
Veja mais de perto o código acima. Depois de validar os dados que chegam pela propriedade $request
, suas credenciais da Twilio armazenadas no arquivo .env
são recuperadas usando a função PHP getenv() integrada. Em seguida, eles são passados para o Twilio Client para criar uma nova instância. Depois disso, o serviço verify (verificar)
é acessado na instância do Twilio Client usando:
$twilio->verify->v2->services($twilio_verify_sid)
->verifications
->create($data['phone_number'], "sms");
O serviço Twilio Verify sid
também foi passado para service (serviço)
que permite o acesso ao serviço Twilio Verify que você criou anteriormente neste tutorial. Em seguida, o método ->verifications->create()
foi chamado passando o número de telefone a ser verificado e um canal para entrega. A senha de uso único pode ser mail
, sms
ou call
. No momento, você está usando o canal sms
, o que significa que seu código OTP será enviado ao usuário via SMS. Em seguida, os dados do usuário são armazenados no banco de dados usando o método Eloquent create:
User::create([
'name' => $data['name'],
'phone_number' => $data['phone_number'],
'password' => Hash::make($data['password']),
]);
Depois disso, o usuário é redirecionado para uma página verify
que envia seu phone_number
como dados para a exibição.
Como verificar a OTP do número de telefone
Após o registro do usuário, você precisará criar uma maneira de verificar a OTP enviada a ele por meio de seu channel
escolhido. Crie um método verify
a ser usado para verificar o número de telefone do usuário em relação ao código OTP inserido em seu formulário. Abra app/Http/Controllers/AuthController.php
e adicione o seguinte método:
protected function verify(Request $request)
{
$data = $request->validate([
'verification_code' => ['required', 'numeric'],
'phone_number' => ['required', 'string'],
]);
/* Get credentials from .env */
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio_sid = getenv("TWILIO_SID");
$twilio_verify_sid = getenv("TWILIO_VERIFY_SID");
$twilio = new Client($twilio_sid, $token);
$verification = $twilio->verify->v2->services($twilio_verify_sid)
->verificationChecks
->create($data['verification_code'], array('to' => $data['phone_number']));
if ($verification->valid) {
$user = tap(User::where('phone_number', $data['phone_number']))->update(['isVerified' => true]);
/* Authenticate user */
Auth::login($user->first());
return redirect()->route('home')->with(['message' => 'Phone number verified']);
}
return back()->with(['phone_number' => $data['phone_number'], 'error' => 'Invalid verification code entered!']);
}
Assim como no método register()
, os dados acima são recuperados da solicitação e instanciam o SDK da Twilio com suas credenciais antes de acessar o serviço verify
. Vejamos como isso é estruturado:
$verification = $twilio->verify->v2->services($twilio_verify_sid)
->verificationChecks
->create($data['verification_code'], array('to' => $data['phone_number']));
Do exposto acima, você pode dizer que está acessando o serviço Twilio Verify como antes, mas desta vez você está fazendo uso de outro método disponibilizado por meio do serviço:
->verificationChecks->create($data['verification_code'], array('to' => $data['phone_number']));
A função create()
aceita dois parâmetros, uma string
do código OTP enviado ao usuário e uma matriz com uma propriedade to
, cujo valor é o número de telefone do usuário para o qual a OTP foi enviada. O método verificationChecks->create()
retorna um objeto que contém várias propriedades, incluindo uma propriedade booleana valid
, que é ou true
ou false
, dependendo de a OTP inserida ser válida ou não:
if ($verification->valid) {
$user = tap(User::where('phone_number', $data['phone_number']))->update(['isVerified' => true]);
/* Authenticate user */
Auth::login($user->first());
return redirect()->route('home')->with(['message' => 'Phone number verified']);
}
return back()->with(['phone_number' => $data['phone_number'], 'error' => 'Invalid verification code entered!']);
Em seguida, o código verifica se a propriedade valid (válida) é verdadeira e, em seguida, prossegue para atualizar o campo isVerified
do usuário para true
. Em seguida, o aplicativo continua a autenticar manualmente o usuário usando o método Auth::login
do Laravel, que fará login e lembrará a instância do modelo User (Usuário) fornecida.
Observação: o modelo de usuário deve implementar a interface autenticável antes que ela possa ser usada com o método Auth::login do Laravel.
Após a verificação do usuário, ele é redirecionado para o dashboard do aplicativo.
Como criar as exibições
Toda a lógica para registrar e verificar um usuário foi escrita. Agora vamos criar a exibição que o usuário usará para interagir com seu aplicativo. Será necessário um layout que sirva como a interface principal de seu aplicativo. Crie uma pasta chamada layouts
em resources/views/
. Em seguida, crie um arquivo chamado app.blade.php
na pasta layouts
. Agora abra o arquivo recém-criado (resources/views/layouts/app.blade.php
) e adicione o seguinte:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Styles -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ml-auto">
<!-- Authentication Links -->
@guest
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }} <span class="caret"></span>
</a>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
</main>
</div>
</body>
</html>
Nota: para agilizar a criação deste aplicativo, o Bootstrap está sendo utilizado para criar seu aplicativo e formulários.
Em seguida, crie uma pasta chamada auth em resources/views/
. Agora, crie os seguintes arquivos e cole-os em seu respectivo conteúdo. Em resources/views/auth/register.blade.php
:
@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="phone_number" 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" name="phone_number" value="{{ old('phone_number') }}" required>
@error('phone_number')
<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 mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Register') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
e agora em resources/views/auth/verify.blade.php
:
@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">{{ __('Verify Your Phone Number') }}</div>
<div class="card-body">
@if (session('error'))
<div class="alert alert-danger" role="alert">
{{session('error')}}
</div>
@endif
Please enter the OTP sent to your number: {{session('phone_number')}}
<form action="{{route('verify')}}" method="post">
@csrf
<div class="form-group row">
<label for="verification_code"
class="col-md-4 col-form-label text-md-right">{{ __('Phone Number') }}</label>
<div class="col-md-6">
<input type="hidden" name="phone_number" value="{{session('phone_number')}}">
<input id="verification_code" type="tel"
class="form-control @error('verification_code') is-invalid @enderror"
name="verification_code" value="{{ old('verification_code') }}" required>
@error('verification_code')
<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">
{{ __('Verify Phone Number') }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
Por fim, crie uma página para a qual os usuários verificados serão levados criando um arquivo chamado home.blade.php
em resources/views/
. Adicione o seguinte conteúdo (resources/views/home.blade.php
):
@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">Dashboard</div>
<div class="card-body">
@if (session('message'))
<div class="alert alert-success" role="alert">
{{ session('message') }}
</div>
@endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
@endsection
Como atualizar as rotas
Incrível! Agora que você concluiu a criação da exibição, vamos atualizar o arquivo routes/web.php
com as rotas necessárias para o aplicativo. Abra routes/web.php
e faça as seguintes alterações:
<?php
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('auth.register');
})->name('register');
Route::get('/verify', function () {
return view('auth.verify');
})->name('verify');
Route::get('/home', function () {
return view('home');
})->name('home');
Route::post('/', 'AuthController@create')->name('register');
Route::post('/verify', 'AuthController@verify')->name('verify');
Como testar o aplicativo
Agora que você terminou de criar o aplicativo, vamos testá-lo. Abra a janela do console e navegue até o diretório do projeto e execute o seguinte comando:
$ php artisan serve
Ele mostrará o aplicativo Laravel em uma porta localhost, que normalmente é 8000. No navegador, abra o link localhost que aparece depois da execução do comando e você verá uma página de registro semelhante a esta:
Preencha o formulário de registro para acionar o envio de um código OTP. Você usará esse código ao preencher o formulário na página para a qual foi redirecionado.
Conclusão
Ótimo! Ao concluir este tutorial, você aprendeu a usar o serviço de verificação da Twilio para validar números de telefone em um aplicativo Laravel. Além disso, aprendemos a autenticar manualmente um usuário em um aplicativo do Laravel. Se você quiser dar uma olhada no código-fonte completo deste tutorial, ele está disponível no Github.
Este artigo foi traduzido do original “How to Verify Phone Numbers in a Laravel PHP Application with Twilio Verify“. 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.