https://a.storyblok.com/f/270183/72193/6d3f1d867f/mongodb_vonage_p2.png

Utilizando as APIs da Vonage com o MongoDB Atlas – Parte 2

Publicado em May 4, 2023

Tempo de leitura: 10 minutos

Nesta série:

Continuamos nossa análise aprofundada do MongoDB Atlas e seu uso com diversas APIs da Vonage. Na Parte 1, vimos exatamente o que é o MongoDB Atlas e alguns dos serviços que ele oferece. Na Parte 2, vamos nos aprofundar no aplicativo de exemplo para ver como podemos usar o MongoDB para dar suporte ao nosso processo de cadastro, bem como integrar o Vonage Verify para aumentar a segurança dos usuários.

O que é o Vonage Verify?

Vonage Verify é uma autenticação de dois fatores que a Vonage oferece como uma API. Ele permite que você faça uma simples chamada de API para enviar um código a um usuário e, em seguida, verifique sua validade com outra chamada de API. Isso proporciona segurança adicional, garantindo que o usuário não apenas saiba sua senha, mas também tenha um dispositivo físico que nos tenha informado para receber o código. Como a maioria das pessoas possui um dispositivo móvel, é bastante seguro presumir que elas terão acesso para receber o código nele.

O Vonage Verify gera o código e entra em contato com o cliente em seu nome. Também tentaremos entrar em contato com o cliente várias vezes, de diversas maneiras. Por exemplo, se você não tentar validar o código de um cliente dentro de um determinado prazo, tentaremos ligar para ele com uma mensagem automatizada para fornecer o código. Se ele ainda assim não inserir o código ou não atender a ligação, tentaremos enviar uma mensagem de SMS novamente. Você pode controlar como tentamos entrar em contato com o cliente por meio dos chamados “fluxos de trabalho”.

Nosso produto Verify, da versão anterior, oferece suporte a SMS e chamadas de Voice para entrar em contato com o cliente. Verify oferece suporte a canais de autenticação como SMS, Voice, WhatsApp, e-mail e autenticação baseada em dispositivo, com fluxos de trabalho totalmente personalizáveis. Ambos os produtos poupam você de ter que enviar notificações manualmente aos seus clientes e acompanhar suas respostas, além de não precisar se preocupar com o envio de mensagens de reclamação ou com o risco de ser bloqueado pelos filtros de spam das operadoras de telefonia.

Basta você nos enviar uma solicitação de API, nós enviamos o código e você o verifica.

Criação de um banco de dados

Para que nossa demonstração funcione, precisamos de alguns pratos para os usuários pedirem! Inserir informações em um banco de dados MongoDB é um pouco diferente de inserir dados em um Sistema de Gerenciamento de Banco de Dados Relacional tradicional, como o Postgres ou o MySQL. O MongoDB é um sistema baseado em documentos; portanto, em vez de criar um banco de dados com tabelas, criaremos um banco de dados com coleções. Essas coleções armazenarão documentos, que são documentos especiais semelhantes a JSON que podemos pesquisar e utilizar.

Vamos criar nosso primeiro banco de dados. No painel do MongoDB Atlas, clique em botão “Navegar pelas coleções” do seu cluster.

MongoDB DashboardMongoDB Dashboard

Isso levará você a uma tela com todas as informações do seu cluster. No momento, ela está bem vazia, pois não temos bancos de dados nem informações. Vamos adicionar alguns itens alimentícios para os usuários comprarem. Clique no botão “Meus próprios dados” .

Adding DataAdding Data

Em seguida, será solicitado o nome do banco de dados e o nome da coleção. Para nossa demonstração, queremos “restaurant_pos_demo” como nome do banco de dados e “inventory” para o nome da coleção. A demonstração já está configurada para procurar por esse banco de dados e essa coleção; portanto, certifique-se de usar esses nomes em vez de nomes personalizados. Depois de inserir essas informações, clique no botão Criar .

Create new CollectionCreate new Collection

Agora podemos inserir alguns dados. Clique no botão “Inserir documento” . Isso abrirá o editor de documentos. Embora ele ofereça um conjunto razoável de menus suspensos para inserir informações, também podemos simplesmente colar alguns documentos. Clique no {} na parte superior para alternar para o modo de inserção de texto e cole o pequeno bloco de JSON referente ao documento “Hamburger”. Clique em Inserir, e o item do inventário será salvo. Repita o procedimento, mas, na segunda vez, cole o documento “Soda”.

// Document 1
{
  "name": "Hamburger",
  "price": 995
}

// Document 2
{
  "name": "Soda",
  "price": 199
}

Document EditorDocument Editor

Depois de inserir os dois documentos, você poderá visualizá-los na visualização do banco de dados. Esse editor é uma ótima maneira de experimentar com documentos e dados enquanto você constrói seu banco de dados, e pode economizar muito tempo durante a fase de desenvolvimento na depuração de dados. Em um ambiente de produção maior, você pode executar consultas para filtrar os dados, mas, por enquanto, essa é uma boa maneira rápida de inserir nossos dados.

DocumentsDocuments

Configurar a demonstração

Agora que já temos alguns dados, podemos montar nossa demonstração. Clone a demonstração a partir de https://github.com/Vonage-Community/sample-mongodb-vonage-integration-restaurant-demo. Há duas pastas: a pasta “webapp”, com o código-fonte, e a pasta “app-service”, com algumas configurações do MongoDB que usaremos mais tarde. Por enquanto, acesse a pasta “webapp” e abra-a no seu editor preferido.

Precisamos adicionar alguns detalhes de configuração para que o aplicativo saiba como se comunicar com o seu cluster do MongoDB. Faça uma cópia do .env.dist arquivo no repositório e nomeie-o como .env. Esse arquivo conterá todas as informações específicas da sua instalação.

Abra .env e faça as seguintes alterações:

  1. Altere “ENABLE_VERIFY” para “1” para que possamos ver a Verify API do Vonage Verify em ação

  2. Defina “VONAGE_API_KEY” com a chave da API da Vonage disponível no seu Painel do Cliente da Vonage

  3. Defina “VONAGE_API_SECRET” com o segredo da API da Vonage disponível no seu Painel do Cliente da Vonage

  4. Altere o valor de “JWT_SIGNING_KEY” para algum valor aleatório. A string em si não importa, mas vamos usá-la mais tarde para validar chamadas de API.

Também precisaremos definir o valor de “MONGODB_DSN” como a string de conexão do seu cluster. Para encontrar esse valor, acesse o painel do MongoDB Atlas e clique no botão “Conectar” do seu cluster. Na janela pop-up, clique em Conectar seu aplicativo. Isso levará você a uma tela que exibe sua string de conexão. Copie esse valor e cole-o no campo “MONGODB_DSN” em .env. Certifique-se de substituir a <password> parte por a senha do seu cluster.

Connecting to the applicationConnecting to the application

Agora já devemos conseguir rodar a demonstração!

Executando a demonstração

A demonstração em si foi desenvolvida usando Vite, Vue.js e TypeScript. Para executá-la, precisamos rodar tanto o aplicativo cliente (front-end) quanto o aplicativo servidor (back-end). Abra dois terminais de linha de comando.

No primeiro terminal, na webapp/ pasta, execute npm ci para instalar todas as dependências e, em seguida, execute npm run dev. Se tudo correr bem, você deverá ver uma tela com a mensagem “Vite <version>" e, em seguida, um link para Local, provavelmente apontando para http://localhost:5173. Seu link pode ser um pouco diferente se houver outros serviços escutando na porta 5173.

No segundo terminal, acesse webapp/server. Assim como na outra janela, execute npm ci para instalar todas as dependências e, em seguida, execute npm run dev. Essa tela deve mostrar nodemon o comando “start” e, eventualmente, a mensagem “Server Started”. Se você receber uma mensagem de erro informando que não é possível se conectar, verifique a string de conexão do seu cluster do MongoDB.

Starting the demoStarting the demo

Abra seu navegador e acesse http://localhost:5173/website/login (substitua o número da porta pelo que o Vite indicar que está em execução no seu caso). Você deverá ver a seguinte tela de login!

Login PageLogin Page

Testando o Verify

No momento, não temos usuários, então vamos criar um. Clique no Ou inscreva-se no link “flavor” na página. Digite um nome de usuário, uma senha e um número de celular. Seu número deve incluir o código de país e não deve conter traços. Enviaremos um código de autenticação de dois fatores para esse número de celular como parte do login do usuário; portanto, certifique-se de usar um número de celular real, e não um número do Google Voice. Se você estiver nos EUA, um exemplo seria “15556661234”.

Depois de inserir suas informações de usuário, clique em “Registrar-se”.

Agora você já deve conseguir fazer login. Digite o nome de usuário e a senha com os quais acabou de se cadastrar. Se a autenticação for bem-sucedida, você será direcionado a um pequeno formulário solicitando que digite seu código de autenticação de duas etapas (2FA).

M2FA Form2FA Form

Após alguns segundos, você deverá receber um SMS com um código de quatro dígitos. Insira esse código no formulário e clique em Enviar. Se tudo der certo, você verá uma tela de pedido com nosso hambúrguer e refrigerante!

Como isso funciona?

Quando o usuário faz login, nosso aplicativo do lado do cliente em Vue.js envia o nome de usuário e a senha para o nosso servidor de back-end, mais especificamente /api/website/authenticate. Essa rota se conecta diretamente ao nosso cluster do MongoDB e localiza o usuário em uma users coleção. Quando registramos um novo usuário, o MongoDB criou automaticamente a coleção para nós e armazenou um documento para o usuário. Recuperamos esse documento e, em seguida, comparamos a senha com a cópia com hash armazenada no documento.

O cliente Node.js do MongoDB é um cliente fluente, o que significa que podemos encadear chamadas de métodos para gerar uma consulta. A linha:

const userRecord = await client.db('restaurant_pos_demo').collection('users').findOne({ username });

instruir o cliente do MongoDB a usar nosso banco de dados “restaurant_pos_demo”, pesquisar na coleção “users” e localizar um documento com o “username” fornecido na solicitação. Como armazenamos a senha como um hash bcrypt, podemos usar bcrypt.compare() para comparar a senha fornecida pelo usuário com a que armazenamos no documento do usuário. Se elas corresponderem, o usuário digitou a senha correta!

// webapp/server/server.ts

app.all('/api/website/authenticate', async (req, res) => {
    const { username, password } = req.body
    const userRecord = await client.db('restaurant_pos_demo').collection('users').findOne({ username });

    if (userRecord) {
        await bcrypt.compare(password, userRecord.password)
            .then(async (match) => {
                if (match) {
                    const token = jwt.sign({user_id: userRecord._id }, process.env.JWT_SIGNING_KEY, { expiresIn: '15m'})
                    let verifyId = {request_id: 'abcd'};
                    if (process.env.ENABLE_VERIFY === "1") {
                        verifyId = await vonage.verify.start({number: userRecord.phone, brand: 'Vonage Restaurant'})
                        console.log(verifyId);
                    } else {
                        console.log('Verify Disabled');
                    }
                    
                    res.status(200).json({ token, verifyId: verifyId.request_id })
                } else {
                    res.status(401).send()
                }
            })
        return
    }

    res.status(401)
    res.send()
    return
})

Em seguida, geramos um JWT temporário para enviar de volta ao aplicativo Vue.js. Nosso aplicativo Vue.js utilizará esse JWT temporário quando o usuário inserir o código no aplicativo do lado do cliente. Se Verify estiver habilitado na demonstração com “ENABLE_VERIFY”, usamos o SDK do Vonage para Node.js para chamar a Verify API. Passamos o número de telefone do usuário e definimos a marca como “Vonage Restaurant”. Quando o usuário receber uma mensagem SMS ou uma chamada de voz, ela será identificada como “Vonage Restaurant” no momento do recebimento.

A API da Vonage retorna um “ID de solicitação”. Também enviaremos esse ID de volta ao front-end e o utilizaremos para verificar o código fornecido pelo usuário. Em seguida, enviamos o token JWT temporário e o ID de solicitação de volta ao aplicativo Vue.js.

Depois de Verifymos que o usuário era quem dizia ser, alteramos o formulário do Vue.js para solicitar o código de autenticação de duas etapas (2FA). Quando o usuário insere o código, o aplicativo Vue.js envia uma solicitação para /api/website/authenticate/verify com o token, o ID da solicitação de Verify e o código digitado pelo usuário.

O JWT contém o ID do documento do usuário; portanto, decodificamos o token e procuramos o usuário no MongoDB. Se o encontrarmos, chamamos a Verify API, mas, desta vez, usamos o check() método e enviamos junto o ID da solicitação e o código. A API retornará um resultado positivo se o código corresponder. Se corresponder, geramos um JWT válido com prazo de validade mais longo e o retornamos ao aplicativo Vue.js.

// webapp/server/server.ts

app.all('/api/website/authenticate/verify', async (req, res) => {
    const { token, verifyId, tfaPin } = req.body
    const decodedToken = jwt.decode(token)
    const userRecord = await client.db('restaurant_pos_demo').collection('users').findOne({ _id: new ObjectId(decodedToken.user_id) });

    if (userRecord) {
        if (process.env.ENABLE_VERIFY === "1") {
            await vonage.verify.check(verifyId, tfaPin)
                .then(resp => {
                    console.log(resp)
                    const token = jwt.sign({user_id: userRecord._id }, process.env.JWT_SIGNING_KEY, { expiresIn: '2h'})
                    res.status(200).json({ token })
                })
                .catch(err => {
                    console.error("there was an error", err);
                })
            return
        } else {
            const token = jwt.sign({user_id: userRecord._id }, process.env.JWT_SIGNING_KEY, { expiresIn: '2h'})
            res.status(200).json({ token })
        }
    }

    res.status(500)
    res.send()
    return
})

O aplicativo Vue.js sabe que estamos totalmente autenticados assim que recebe o JWT correto. Ele armazena esse token em um repositório global chamado “authenticationStore”, e o restante do aplicativo utilizará esse JWT para autenticar o usuário em quaisquer chamadas de API futuras.

// src/views/Website/Login.vue

const verify = async() => {
    fetch(import.meta.env.VITE_API_URL + '/api/website/authenticate/verify', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            token: tempJWT.value,
            verifyId,
            tfaPin: tfaPin.value
        })
    })
        .then(resp => resp.json())
        .then(async (json) => {
            console.log(json)
            authStore.setToken(json.token)
            router.push({ name: 'website.order' });
            
            return
        })
        .catch(err => console.log(err)); 
}

Conclusão

Se você já possui uma etapa de autenticação em seu aplicativo, adicionar o Vonage Verify requer apenas algumas linhas de código a mais. Para nosso aplicativo Vue.js, isso significou uma chamada adicional ao nosso backend e um novo formulário; já no lado do servidor, bastou fazer a chamada à API para enviar o código e, em seguida, criar uma nova rota para verificar o código. Como a Vonage cuida de todo o trabalho pesado de gerar, enviar e verificar o código, o impacto em nossa base de código é mínimo. A flexibilidade do armazenamento baseado em documentos do MongoDB fez com que não precisássemos executar nenhuma migração de banco de dados e pudéssemos escrever rapidamente o código para inserir um novo usuário e fazer as consultas.

Agora que nossos usuários já podem fazer login, é hora de pedirem algo para comer!

Na próxima seção, veremos como usar o MongoDB para armazenar o pedido e a SMS API da Vonage para enviar uma confirmação do pedido. Também daremos uma olhada no uso da Meetings API do Vonage para adicionar rapidamente videoconferência ao nosso aplicativo, a fim de resolver questões de atendimento ao cliente.

Compartilhar:

https://a.storyblok.com/f/270183/384x384/3bc39cbd62/christankersley.png
Chris TankersleyGerente de Ferramentas de Relações com Desenvolvedores

Chris é o gerente de ferramentas de relações com desenvolvedores e lidera a equipe responsável pelo desenvolvimento das suas ferramentas favoritas. Ele programa há mais de 15 anos, utilizando diversas linguagens e trabalhando em vários tipos de projetos, desde trabalhos para clientes até big data e sistemas de grande escala. Ele mora em Ohio, onde passa o tempo com a família e jogando videogames e RPGs de mesa.