Como adicionar autenticação a um aplicativo React Native?

Capa de autenticação do React Native (Expo)

A autenticação é um componente essencial de quase todos os aplicativos.

Este artigo prático fornecerá um guia passo a passo para começar a usar a autenticação do React Native.

Além disso, ele descreverá os fundamentos da autenticação, como ela se compara à autorização, o fluxo de autenticação e os benefícios de usá-la.

O que é autenticação?

A autenticação é o processo de verificação da identidade de alguém. De modo geral, há três maneiras de autenticar com:

  1. Algo que você sabe (por exemplo, senha, PIN)
  2. Algo que você tenha (por exemplo, telefone celular, chaves)
  3. Algo que você é (por exemplo, impressão digital, íris)

A maioria dos aplicativos usa a primeira opção, mas muitos deles combinam várias delas para aumentar o nível de segurança. Esse conceito é chamado de autenticação multifatorial (MFA).

Fluxo de autenticação

O fluxo de autenticação genérico funciona da seguinte forma:

  1. O usuário envia sua senha para o servidor.
  2. O servidor faz o hash da senha e a compara com o hash da senha no banco de dados.
  3. Se os hashes forem iguais, o servidor criará uma sessão e enviará o token de sessão ao usuário. Por outro lado, se os hashes não corresponderem, será gerado um erro.
  4. O usuário usa o token de sessão em cada solicitação. Em cada solicitação, o servidor verificará se o token está presente e é válido.

O fluxo acima é a chamada autenticação de token. Outros sistemas de autenticação incluem JSON Web Token (JWT), autenticação de acesso básico, login social e assim por diante.

Autenticação vs. Autorização

A autenticação é o ato de verificar a identidade de um usuário, enquanto a autorização é o ato de verificar se um usuário tem permissões suficientes para executar uma ação.

Os modelos de autorização incluem controle de acesso obrigatório (MAC), controle de acesso discricionário (DAC) e autorização baseada em função, entre outros.

Benefícios da autenticação

Vejamos alguns benefícios de usar a autenticação em seus aplicativos móveis.

Segurança

A autenticação pode proteger seu aplicativo contra acesso não autorizado e garantir que somente usuários legítimos tenham acesso ao seu serviço.

Isso ajuda a evitar violações de dados e ataques cibernéticos e mantém o ambiente do seu aplicativo seguro e confiável.

Personalização

A autenticação permite uma experiência de usuário personalizada no aplicativo. Quando os usuários fazem login, eles podem acessar configurações personalizadas, preferências e recomendações adaptadas às suas necessidades.

Essa personalização torna o aplicativo mais envolvente e fácil de usar. Ela ajuda a reter os usuários ao proporcionar uma experiência mais relevante e agradável.

Requisitos legais

As leis de alguns países exigem que você verifique a identidade dos seus usuários. Um exemplo disso é o Know Your Customer (KYC).

Quase todos os aplicativos financeiros são obrigados a fazer isso. É preciso ter um sistema de autenticação adequado para estar em conformidade com essas normas ou proteger as informações pessoais dos usuários.

Como adicionar autenticação a um aplicativo React Native?

Esta parte do artigo fornecerá um guia passo a passo sobre como adicionar a autenticação do Back4app a um aplicativo React Native(Expo).

Pré-requisitos

  • Conhecimento básico de back-end como serviço (BaaS)
  • IDE JavaScript, Node.js e um emulador móvel ou um dispositivo físico
  • Capacidade de ler e escrever código JavaScript
  • Experiência com React Native e Expo
  • Uma conta gratuita no Back4app

O que é o Back4app?

O Back4app é uma das melhores soluções de Backend as a Service (BaaS) de código aberto. É uma plataforma madura e confiável que existe desde 2015.

Seus principais recursos incluem bancos de dados em tempo real, funções do Cloud Code, geração automática de API RESTful/GraphQL e muito mais!

O Back4app tem um painel de administração fácil de usar e intuitivo e uma interface de linha de comando (CLI) para usuários mais avançados.

Ele também fornece SDKs para as linguagens e estruturas de programação mais populares, como JavaScript, PHP, Flutter e Dart.

A melhor parte é que o Back4app oferece um nível gratuito. O nível gratuito é ótimo para testes e prototipagem e inclui o seguinte:

  • 25 mil solicitações mensais
  • 250 MB de armazenamento de dados
  • Transferência de dados de 1 GB
  • 1 GB de armazenamento de arquivos

Por que usar o Back4app?

  • Suporte à autenticação social
  • Fornece SDKs para a maioria das linguagens e estruturas de programação
  • Fácil de configurar e usar
  • Excelente suporte ao cliente

Para saber como a autenticação do Back4app se compara à autenticação do Firebase, confira O guia definitivo para autenticação do React Firebase.

Introdução ao projeto – Primeiros passos com a autenticação do React Native

Criaremos um aplicativo React Native pronto para produção que usa a autenticação do Back4app. O aplicativo permitirá que os usuários se registrem, façam login e gerenciem seus perfis.

Além disso, o aplicativo terá duas guias de navegação, uma para usuários autenticados e outra para usuários não autenticados.

O produto final terá a seguinte aparência:

Aplicativo nativo React de autenticação Back4app

Vamos começar a programar!

Backend (Back4app)

Nesta seção, criaremos um aplicativo Back4app, estenderemos o modelo de usuário padrão e obteremos as chaves de API necessárias para nos conectarmos ao backend.

Criar aplicativo

Primeiro, faça login na sua conta do Back4app ou crie uma, caso ainda não a tenha.

Ao fazer login, você será redirecionado para a sua lista de aplicativos. Clique em “Build new app” (Criar novo aplicativo) para criar um novo aplicativo.

Lista de aplicativos do Back4app

A plataforma Back4app permite que você implemente dois tipos de aplicativos: Backend as a Service (BaaS) ou Containers as a Service (CaaS). A autenticação está incluída no BaaS, portanto, selecione-a.

Back4app Backend as a Service Select

Em seguida, dê ao seu aplicativo um nome descritivo, deixe o banco de dados como NoSQL e clique em “Create”.

Configuração do aplicativo Back4app

Aguarde cerca de dois minutos para que a plataforma crie o aplicativo. O Back4app fará tudo, desde a criação da camada do aplicativo até a configuração do banco de dados, segurança, dimensionamento e muito mais.

Depois disso, você será redirecionado para a interface do banco de dados.

Visualização do banco de dados do Back4app

Modificar banco de dados

A seguir, vamos falar sobre as classes de banco de dados.

Cada classe de banco de dados do Back4app vem com os seguintes campos padrão:

+-----------+------------+-----------------------------------------+
| Data type | Name       | Description                             |
+-----------+------------+-----------------------------------------+
| String    | objectId   | Object's unique identifier              |
+-----------+------------+-----------------------------------------+
| Date      | createdAt  | Date of object creation                 |
+-----------+------------+-----------------------------------------+
| Date      | updatedAt  | Date of object's last update            |
+-----------+------------+-----------------------------------------+
| ACL       | ACL        | Access Control List (security features) |
+-----------+------------+-----------------------------------------+

E a classe User vem com alguns campos adicionais:

+-----------+----------------+--------------------------+----------+
| Data type | Name           | Default value            | Required |
+-----------+----------------+--------------------------+----------+
| String    | username       |                          | yes      |
+-----------+----------------+--------------------------+----------+
| String    | email          |                          | no       |
+-----------+----------------+--------------------------+----------+
| Boolean   | emailVerified  | false                    | no       |
+-----------+----------------+--------------------------+----------+
| String    | password       |                          | yes      |
+-----------+----------------+--------------------------+----------+
| Object*   | authData       | {}                       | yes      |
+-----------+----------------+--------------------------+----------+

A classe de usuário padrão do Back4app deve ser boa para a maioria dos casos de uso. No entanto, é fácil ampliá-la. Para demonstrar como isso é feito, vamos adicionar um campo de biografia(bio).

Primeiro, clique no botão “+ Column” acima da tabela do banco de dados.

Banco de dados do Back4app Adicionar coluna

No formulário de criação de coluna, selecione “String” como tipo de dado, defina o nome como bio, torne-o obrigatório e clique em “Add” (Adicionar).

Back4app Add Database Field (Adicionar campo de banco de dados)

Ótimo, agora você sabe como funcionam as classes de banco de dados do Back4app e como estender o modelo de usuário.

Chaves de API

Você precisará obter as chaves de API do seu aplicativo para se conectar ao backend a partir do frontend.

Para obtê-las, navegue até o aplicativo Back4app e selecione “Security & Keys” (Segurança e chaves) na barra lateral. Observe a “Client key” e a “JavaScript key”.

Chaves de API do Back4app

Ótimo, isso é tudo do lado do backend.

Front-end (React Native)

Nesta seção, criaremos um aplicativo Expo, instalaremos uma biblioteca de componentes, configuraremos a navegação, cuidaremos das telas e, por fim, conectaremos o frontend ao backend.

Criar aplicativo

Para criar um aplicativo React Native, usaremos o utilitário create-expo-app. Esse utilitário simplifica a criação de aplicativos React Native gerando a estrutura de diretórios, configurando o TypeScript etc.

Primeiro, execute os seguintes comandos:

npx create-expo-app@latest back4app-expo-auth
cd back4app-expo-auth

Esse comando também instalará o create-expo-app se você ainda não o tiver.

Você notará que o projeto bootstraped tem a seguinte estrutura de diretórios:

back4app-expo-auth/
├── app                 - Layouts, screens
├── assets              - Static assets (e.g. images, videos, fonts)
├── components          - Reusable components used through the app
├── constants           - Static variables & configurations
├── hooks               - Custom React hooks
├── scripts             - Development scripts
├── app.json            - Expo configuration & metadata
├── expo-env.d.ts       - Expo TypeScript declarations
├── ...    

Inicie o servidor de desenvolvimento:

$ npx expo start

Por fim, pressione A para abrir o aplicativo em seu emulador de Android. Como alternativa, você pode usar o emulador de iOS ou um dispositivo iOS físico. Quando o aplicativo for aberto, você verá a tela padrão da Expo.

Tela padrão da Expo

React Native Paper

Para simplificar o processo de desenvolvimento da interface do usuário, usaremos o React Native Paper.

O React Native Paper é uma biblioteca de componentes de alta qualidade e fácil de usar para aplicativos React Native. Ela fornece muitos componentes pré-fabricados que abrangem quase todos os casos de uso.

Comece instalando-o via NPM:

$ npm install react-native-paper react-native-safe-area-context 

Se estiver criando para iOS, também terá que vincular partes nativas da biblioteca:

npx pod-install

Em seguida, configure o Babel para não incluir componentes não utilizados na produção:

// babel.config.js

module.exports = function(api) {
  api.cache(true);
  return {
    presets: ["babel-preset-expo"],
    env: {
      production: {
        plugins: ["react-native-paper/babel"],
      },
    },
  };
};

Em seguida, navegue até app/_layout.tsx e envolva o aplicativo no PaperProvider da seguinte forma:

// app/_layout.tsx

// ...

export default function RootLayout() {

  // ...

  return (
    <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
      <PaperProvider>
        <Stack>
          <Stack.Screen name="index" options={{headerShown: false}}/>
          <Stack.Screen name="(auth)" options={{headerShown: false}}/>
          <Stack.Screen name="(tabs)" options={{headerShown: false}}/>
          <Stack.Screen name="+not-found"/>
        </Stack>
      </PaperProvider>
    </ThemeProvider>
  );
}

Não se esqueça da importação na parte superior do arquivo:

import {PaperProvider} from "react-native-paper";

Perfeito, instalamos a biblioteca de componentes com sucesso.

Contêineres

Outra coisa que faremos é criar um componente Container. Esse componente será usado em todas as nossas telas e adicionará uma margem em todos os lados para que o conteúdo não vá para a borda da tela.

Crie um arquivo Container.tsx na pasta de componentes:

// components/Container.tsx

import React from "react";
import {View} from "react-native";

export type ContainerProps = {
  children: React.ReactNode;
}

export function Container({children}: ContainerProps) {
  return (
    <View style={{margin: 12}}>
      {children}
    </View>
  );
}

Navegação e telas

Conforme mencionado na introdução do projeto, nosso aplicativo terá duas guias de navegação.

Uma é para usuários autenticados e a outra é para usuários não autenticados. A guia autenticada permitirá que os usuários gerenciem seus perfis e a outra para fazer login ou criar uma conta.

Para isso, primeiro crie a seguinte estrutura de diretórios:

app/
├── (auth)/
│   ├── _layout.tsx
│   ├── login.tsx
│   └── register.tsx
├── (tabs)/
│   ├── _layout.tsx
│   └── profile.tsx
├── +html.tsx
├── +not-found.tsx
├── _layout.tsx
└── index.tsx

Para obter mais informações sobre o Expo Router, consulte a documentação oficial.

Os layouts da Expo geralmente contêm muito código padrão. Não quero encher o artigo com código, portanto, pegue o conteúdo do arquivo no GitHub:

  1. (auth)/_layout.tsx
  2. (guias)/_layout.tsx
  3. _layout.tsx

Continuando, coloque o seguinte em index.tsx:

// app/index.tsx

import React, {useEffect} from "react";
import {ActivityIndicator} from "react-native-paper";
import {useRouter} from "expo-router";
import {View} from "react-native";

export default function IndexScreen() {

  const router = useRouter();
  const isAuthenticated = true;

  useEffect(() => {
    setTimeout(() => {
      if (isAuthenticated) {
        router.push("profile");
      } else {
        router.push("login");
      }
    }, 1000);
  }, []);

  return (
    <View style={{
      flex: 1,
      justifyContent: "center",
      alignItems: "center",
    }}>
      <ActivityIndicator
        size="large"
        animating={true}
      />
    </View>
  );
}

O arquivo index.tsx é o ponto de entrada do aplicativo. Nele, verificamos se o usuário está autenticado e, em seguida, o redirecionamos de acordo. Por enquanto, o redirecionamento é baseado na variável isAuthenticated.

Em seguida, pegue o código para as telas:

  1. app/(auth)/login.tsx
  2. app/(auth)/register.tsx
  3. app/(tabs)/profile.tsx

O código das telas é bastante simples. É um código React Native que usa o React Native Paper para criar os formulários e outras interfaces de usuário. Ele também utiliza ganchos básicos do React, como useState() e useEffect().

SDK do Parse

Para nos conectarmos ao backend, usaremos o Parse SDK. O SDK oferece métodos para armazenamento de dados, manipulação, autenticação de usuários e outros recursos.

Primeiro, instale-o via NPM:

$ npm install parse @react-native-async-storage/async-storage --save
$ npm install --save-dev @types/parse

Também instalamos o pacote @react-native-async-storage/async-storage para manter a sessão do usuário quando o aplicativo for fechado. Sem ele, os usuários teriam que se autenticar sempre que abrissem o aplicativo.

Em seguida, crie um arquivo .env na raiz do projeto da seguinte forma:

EXPO_PUBLIC_APPLICATION_ID=<your-back4app-application-id>
EXPO_PUBLIC_JAVASCRIPT_KEY=<your-back4app-client-key>

Certifique-se de substituir <your-back4app-application-id> e <your-back4app-client-key> pelas chaves de API obtidas na seção de back-end do artigo.

Inicialize o Parse em _layout.tsx da seguinte forma:

// app/_layout.tsx

// ...
import Parse from "parse/react-native.js";
import AsyncStorage from "@react-native-async-storage/async-storage";
import ParseContext from "@/context/parseContext";

Parse.setAsyncStorage(AsyncStorage);
Parse.initialize(
  process.env.EXPO_PUBLIC_APPLICATION_ID ?? "",
  process.env.EXPO_PUBLIC_JAVASCRIPT_KEY ?? "",
)
Parse.serverURL = "https://parseapi.back4app.com/";

async function testParse() {
  try {
    const testMessage = new Parse.Object("TestMessage");
    testMessage.set("message", "Hello, World!");
    await testMessage.save();
  } catch (error) {
    console.log("Error saving the test message: ", error);
  }
}
testParse().then(() => console.log("Successfully connected to Parse!"));

// ...

Também incluímos a função testParse(), que testa a conexão com o Back4app adicionando uma mensagem “Hello, world!” ao banco de dados. Para garantir que a conexão funcione, reinicie o servidor Expo e execute o aplicativo no emulador.

Mensagem de teste do banco de dados do Back4app

Navegue até a visualização do banco de dados do seu aplicativo e verifique se você consegue ver a mensagem.

Se você receber um erro dizendo “Error: crypto.getRandomValues() not supported”. Instale as seguintes dependências:

npm install react-native-get-random-values --save
npm i --save-dev @types/react-native-get-random-values

Em seguida, adicione a importação na parte superior de _layout.tsx (antes de importar o Parse):

import "react-native-get-random-values";

Reinicie o servidor de desenvolvimento; tudo deve funcionar bem.

Para que a instância do Parse esteja disponível em todas as telas, nós a passaremos usando o React Context.

Primeiro, crie um diretório de contexto e coloque o seguinte arquivo parseContext.ts dentro dele:

import {createContext} from "react";

const ParseContext = createContext<typeof Parse | null>(null);

export default ParseContext;

Em seguida, envolva todo o aplicativo com ele, passando a instância do Parse:

// app/_layout.tsx

// ...

return (
  <ParseContext.Provider value={Parse}>
    {/* ... */}
  </ParseContext.Provider>
)

Recuperação e manipulação de dados

Nesta última seção, usaremos o Parse SDK para autenticar o usuário e obter informações sobre ele.

Em vez de repetir o mesmo código em todas as telas, criaremos um gancho useParse. Esse gancho buscará a instância do Parse no contexto, obterá informações do usuário e acionará uma atualização quando tudo estiver pronto.

Crie um novo arquivo chamado useParse.ts na pasta de contexto:

// context/useParse.ts

import {useContext, useEffect, useState} from "react";
import ParseContext from "@/context/parseContext";

export function useParse() {
  const parse = useContext(ParseContext) as typeof Parse;
  const [parseUser, setParseUser] = useState<Parse.User | null>(null);
  const [isParseLoaded, setIsParseLoaded] = useState(false);

  useEffect(() => {
    (async () => {
      try {
        setParseUser(await parse.User.currentAsync());
      } catch (e) {
        console.error(e);
      } finally {
        setIsParseLoaded(true);
      }
    })();

  }, []);

  return {parse, parseUser, isParseLoaded};
}

Em seguida, modifique o index.tsx substituindo isAuthenticated por uma verificação de sessão real:

// app/index.tsx

// ...
import {useParse} from "@/hooks/useParse";

export default function IndexScreen() {

  const router = useRouter();
  const {parse, parseUser, isParseLoaded} = useParse();

  useEffect(() => {
    if (!isParseLoaded) return;
    (async () => {
      if (parseUser) {
        console.log("User is authenticated!");
        console.log(parseUser.toJSON());
        router.replace("/profile");
      } else {
        console.log("User is not authenticated.");
        console.log({});
        router.replace("/(auth)/login");
      }
    })();
  }, [isParseLoaded]);

  return (
    // ...
  );
}

Em seguida, modifique o login.tsx para fazer o login do usuário:

// app/(auth)/login.tsx

// ...
import {useParse} from "@/hooks/useParse";

export default function LoginScreen() {

  const router = useRouter();
  const {parse, parseUser, isParseLoaded} = useParse();

  // ...

  const onLogin = async () => {
    // ...
    try {
      await parse.User.logIn(username, password);
      router.push("/(tabs)/profile");
    } catch (error: any) {
      setError(error.message);
    }
  }

  return (
    // ...
  );
}

Em seguida, modifique o register.tsx de forma semelhante ao login.tsx, mas, dessa vez, substitua o TODO da seguinte forma:

// app/(auth)/register.tsx

try {
  const user = await parse.User.signUp(username, password, undefined, undefined);
  user.setEmail(email);
  await user.save();
  router.replace("/(tabs)/profile")
} catch (error: any) {
  setError(error.message);
}

Por fim, modifique o profile.tsx para exibir as informações do perfil:

// app/(tabs)/profile.tsx

// ...
import {useParse} from "@/hooks/useParse";

export default function IndexScreen() {

  const router = useRouter();
  const {parse, parseUser, isParseLoaded} = useParse();

  // ...

  useEffect(() => {
    if (!parseUser) return;
    setBio(parseUser.get("bio") || "");
  }, [parseUser]);

  const onSave = async () => {
    if (!parseUser) return;
    parseUser.set("bio", bio);
    try {
      await parseUser.save();
      setSuccess("Bio saved successfully.");
    } catch (error: any) {
      setError(error.message);
    }
  }

  const onLogout = async () => {
    router.replace("/(auth)/login");
    await parse.User.logOut();
  }

  return (
    <Container>
      {!isParseLoaded ? (
        <ActivityIndicator
          size="large"
          animating={true}
        />
      ) : (
        <>
          {/* ... */}
        </>
      )}
    </Container>
  );
}

Lembre-se de alterar as TODOs na chamada de retorno. Use {parseUser!.getUsername()} e {parseUser!.getEmail()}.

Neste ponto, o aplicativo deve estar funcionando plenamente. Reinicie o servidor de desenvolvimento e teste-o criando uma conta, fazendo login, fazendo logout e alterando sua biografia. Por fim, verifique se as alterações estão refletidas no banco de dados.

Conclusão

Concluindo, agora você sabe o que é autenticação, seus benefícios e como ela se compara à autorização.

Além disso, você aprendeu a configurar a autenticação do Back4app e a integrá-la a um aplicativo React Native (baseado em Expo).

Etapas futuras

  1. Saiba mais sobre autenticação social com o Google, o Facebook e a Apple
  2. Dê uma olhada no Back4app Admin App para obter um painel de administração sofisticado em tempo real

O código-fonte final está disponível no GitHub.


Leave a reply

Your email address will not be published.