Como adicionar autenticação a um aplicativo React Native?
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.
Contents
- 1 O que é autenticação?
- 2 Fluxo de autenticação
- 3 Autenticação vs. Autorização
- 4 Benefícios da autenticação
- 5 Como adicionar autenticação a um aplicativo React Native?
- 6 Conclusão
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:
- Algo que você sabe (por exemplo, senha, PIN)
- Algo que você tenha (por exemplo, telefone celular, chaves)
- 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:
- O usuário envia sua senha para o servidor.
- O servidor faz o hash da senha e a compara com o hash da senha no banco de dados.
- 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.
- 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:
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.
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.
Em seguida, dê ao seu aplicativo um nome descritivo, deixe o banco de dados como NoSQL e clique em “Create”.
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.
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.
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).
Ó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”.
Ó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.
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>
);
}
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:
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:
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.
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
- Saiba mais sobre autenticação social com o Google, o Facebook e a Apple
- 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.