Construir aplicativos seguros e escaláveis é um desafio constante para desenvolvedores. A combinação de Prisma com Supabase surge como uma solução robusta, aproveitando o poder do ORM (Object-Relational Mapping) Prisma e o banco de dados PostgreSQL do Supabase. Essa integração facilita a criação de aplicações Next.js com gerenciamento de dados eficiente e seguro, incluindo a criação de triggers para automatizar tarefas como a criação de perfis de usuários.
Adicionando Prisma para Gerenciar Dados no Supabase
Nesta era digital, a segurança dos dados do usuário é primordial. A integração do Prisma com Supabase oferece uma solução poderosa para proteger esses dados, especialmente ao construir aplicações Next.js. O Prisma, com suas capacidades avançadas de ORM, simplifica as operações de banco de dados, enquanto o Supabase fornece um sistema de armazenamento escalável e confiável com PostgreSQL.
A segurança em nível de linha (RLS) é crucial para garantir que os usuários só acessem seus próprios dados. O RLS permite definir políticas de controle de acesso diretamente no banco de dados, aumentando a segurança e a privacidade. Ao integrar o RLS com o sistema de autenticação do Supabase, é possível criar um ambiente seguro onde os usuários gerenciam seus perfis sem comprometer a integridade dos dados. Essa abordagem protege contra acessos não autorizados e simplifica o desenvolvimento, reduzindo a necessidade de lógica complexa no servidor.
Embora a tabela de autenticação no Supabase forneça informações básicas sobre o usuário, armazenar informações extras, como o perfil, em uma tabela separada pode ser útil. Vamos ver como fazer isso.
Configurando o Prisma e Definindo Schemas
Para começar, adicione o Prisma ao seu projeto usando o seguinte comando. Isso instalará o cliente Prisma ORM, facilitando as operações CRUD (Create, Read, Update, Delete) no seu banco de dados Supabase:
pnpm add @prisma/client
Para obter o URL do banco de dados do seu projeto no Supabase, vá para o projeto em que você está trabalhando. No painel esquerdo, clique em “Database” e depois em “Connect” no topo.
Copie o URL do seu banco de dados e cole-o no seu arquivo .env, adicionando as seguintes linhas na parte inferior do arquivo:
.env
DATABASE_URL=postgresql://postgres:[YOUR-PASSWORD]@db.phbngigehmegragywadf.supabase.co:5432/postgres?pgbouncer=true
DIRECT_URL=postgresql://postgres:[YOUR-PASSWORD]@db.phbngigehmegragywadf.supabase.co:5432/postgres
O DIRECT_URL
é o mesmo que o DATABASE_URL
, exceto que ele contém a query pgbouncer
.
Substitua “[YOUR-PASSWORD]” pela senha do seu banco de dados. Se você esqueceu a senha, pode redefini-la em Project Settings > Database > Reset Database Password. Isso não afetará nenhuma outra configuração no projeto Supabase.
Crie uma pasta chamada “prisma” na raiz do seu projeto e, dentro dela, crie um arquivo chamado “schema.prisma”.
A estrutura do schema Prisma define como os dados são organizados no banco de dados. Ele inclui a definição de modelos (tabelas) e seus respectivos campos (colunas), bem como os tipos de dados e as relações entre eles. O schema atua como um contrato entre a aplicação e o banco de dados, garantindo que os dados sejam armazenados e acessados de forma consistente e estruturada.
prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL")
}
model Profile {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
firstName String? @map("first_name")
lastName String? @map("last_name")
email String @unique
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("profiles")
}
Instale a extensão Prisma para VS Code para obter recursos de realce de sintaxe e segurança de tipo do Prisma.
Adicione um script no arquivo package.json
para facilitar as migrações. A migração é o processo de “migrar” seu schema local para criar/modificar as tabelas no seu banco de dados remoto. Adicione a seguinte linha sob a seção scripts
no seu arquivo package.json
.
/package.json
"migrate": "pnpx prisma migrate dev --name init && bunx prisma generate"
Experimente o script de migração. Isso deve criar uma tabela “profiles” no seu banco de dados Supabase. Execute o seguinte comando no terminal:
pnpm migrate
Verifique seu banco de dados no Supabase novamente e confirme se as tabelas foram criadas.
Automatizando a Criação de Perfis com Triggers
Após criar a tabela de perfis, é essencial garantir que um novo perfil seja criado sempre que um novo usuário se inscreve na aplicação e que o usuário seja removido da tabela de autenticação quando exclui seu perfil. Em termos simples:
- Usuário se inscreve → Um registro é adicionado à tabela de autenticação → Criamos um perfil.
- Usuário exclui seu perfil → Um registro é removido da tabela de perfis → Excluímos suas informações de autenticação (conta).
Vá para o seu projeto Supabase e selecione o SQL Editor no painel de navegação esquerdo.
Cole a seguinte query no editor e clique em “Run”.
triggers.sql
-- Creates a function to run when user is authenticated (signed up)
create or replace function public.on_user_signup()
returns trigger as $$
begin
insert into public.profiles (id, email, updated_at, first_name, last_name)
values (
new.id, new.email,
now(),
NEW.raw_user_meta_data->>'first_name',
NEW.raw_user_meta_data->>'last_name'
);
return new;
end;
$$ language plpgsql security definer;
-- Creates a trigger to run the above function when a new user is authenticated (signed up)
create or replace trigger create_user_profile
after insert on auth.users
for each row execute procedure public.on_user_signup();
-- Create a function to delete a user
create or replace function public.on_profile_delete()
returns trigger as $$
begin
delete from auth.users where id = old.id;
return new;
end;
$$ language plpgsql security definer;
-- Creates a trigger to run when a profile is deleted
create or replace trigger delete_auth_user
after delete on public.profiles
for each row execute procedure public.on_profile_delete();
- Primeiro, criamos uma função para criar um novo perfil na tabela Profiles.
- Em seguida, criamos um trigger para executar a função acima quando um novo usuário é autenticado (ou seja, um novo usuário é adicionado à tabela “auth”).
- Então, criamos uma função para excluir o usuário da tabela “auth”.
- Finalmente, criamos um trigger para executar essa função sempre que um perfil é excluído da tabela “Profile”.
Usei create or replace
para que não haja problemas ao executar esta query novamente, caso já exista um trigger ou função com esse nome. Lembre-se de que isso substituirá a função existente (se houver) com o mesmo nome, portanto, tenha cuidado ao executar este script.
Teste essas alterações inscrevendo-se com uma nova conta. Um novo registro deve aparecer na tabela Profile. Vá para o Table Editor (no painel de navegação esquerdo) > profiles e verifique se há um novo registro.
Agora, exclua este registro manualmente daqui e verifique a tabela de autenticação para verificar se os registros estão sendo excluídos lá.
Implementando Segurança em Nível de Linha (RLS)
Recomenda-se acessar seu banco de dados apenas a partir do código do lado do servidor. No entanto, como o Supabase usa chaves públicas que são expostas ao lado do cliente do framework NextJS, precisamos proteger os dados da tabela com RLS.
A segurança em nível de linha (RLS) no PostgreSQL é um recurso que permite aos administradores de banco de dados controlar o acesso a linhas específicas dentro de uma tabela com base em funções de usuário ou outras condições. Isso é feito definindo políticas que atuam como filtros, determinando quais linhas são visíveis ou modificáveis por um usuário durante operações como SELECT, INSERT, UPDATE e DELETE.
Ao usar o Supabase em aplicações do lado do cliente (nosso cliente Next JS), habilitar o RLS é crucial para proteger os dados. Mesmo que a autenticação seja tratada por meio de ações do servidor, habilitar o RLS nas tabelas impede o acesso não autorizado por meio da chave anônima, garantindo que os dados não sejam expostos a usuários não autorizados. Isso fornece uma camada adicional de segurança, atuando como um mecanismo de “defesa em profundidade” para proteger os dados de agentes maliciosos.
Se sua aplicação manipula dados apenas do lado do servidor usando chaves de serviço, as políticas de RLS não são estritamente necessárias. As chaves de serviço podem ignorar o RLS, permitindo que as operações do lado do servidor acessem os dados sem restrições. No entanto, habilitar o RLS sem políticas ainda bloqueia tentativas de acesso não autorizado por meio da chave anônima, fornecendo alguns benefícios de segurança, mesmo em cenários do lado do servidor.
Cole a seguinte query no SQL Editor e execute-a:
-- Enable RLS on profiles table
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
-- ============================================================================
-- Policies for profiles table
-- ============================================================================
-- Policy: Allow users to read their own profile
CREATE POLICY read_own_profile ON profiles
FOR SELECT
USING (auth.uid() = id);
-- Policy: Allow users to update their own profile
CREATE POLICY update_own_profile ON profiles
FOR UPDATE
USING (auth.uid() = id);
-- Policy: Allow users to delete their own profile
CREATE POLICY delete_own_profile ON profiles
FOR DELETE
USING (auth.uid() = id);
Adicionei comentários para cada linha para descrever o que cada linha está fazendo.
No table editor, você pode ver que o ícone de “Open Lock” sumiu da tabela de perfil. Isso significa que nossa tabela de perfil tem o RLS habilitado.
Construir uma aplicação robusta com Next.js e Supabase envolve várias etapas. Começamos configurando um novo aplicativo Next.js, com páginas de autenticação essenciais como Signup, Login, Forgot Password e Reset Password, todas estilizadas com ShadCN e Tailwind CSS. Isso não apenas deu ao nosso aplicativo uma aparência elegante, mas também forneceu uma base sólida para o gerenciamento de usuários.
Em seguida, integramos o Supabase para lidar com a autenticação e proteger nossas rotas, garantindo que os dados confidenciais só sejam acessíveis a usuários autorizados. Também facilitamos o login para nossos usuários, configurando a autenticação do Google, proporcionando uma experiência perfeita. Falando em proteger os seus dados, aqui tem um artigo sobre como os CISOs estão combatendo ataques de deepfake, vishing e engenharia social impulsionados por IA.
Um dos aspectos mais importantes do nosso aplicativo é o gerenciamento avançado de banco de dados. Usamos o Prisma ORM para criar, migrar e consultar tabelas de forma eficiente. Além disso, implementamos a segurança em nível de linha (RLS) em nossas tabelas Supabase PostgreSQL, o que significa que apenas usuários autenticados podem gerenciar os dados que possuem. Essa camada extra de segurança é crucial para manter a integridade dos dados.
Ao longo desta jornada, mostramos como Next.js e Supabase podem ser combinados para construir aplicações seguras e escaláveis. Seja criando um sistema de gerenciamento de usuários ou uma plataforma complexa orientada a dados, as técnicas descritas aqui fornecem uma base sólida para o sucesso. Seguindo estas etapas, os desenvolvedores podem garantir que seus aplicativos atendam às demandas do desenvolvimento web moderno, mantendo os dados seguros.
Confira o código completo desta série aqui.
Este conteúdo foi auxiliado por Inteligência Artificiado, mas escrito e revisado por um humano.
Via Dev.to