Como desenvolvedor, é sua responsabilidade proteger os dados de seus usuários por meio da autenticação. Você pode usar o Passport.js para autenticar usuários em um aplicativo Node e Postgres.
Comece criando um servidor Node com endpoints para registrar, entrar e desconectar usuários. Você pode permitir que o Passport manipule a autenticação para restringir o acesso não autorizado ao seu aplicativo.
Criando uma tabela de usuários
Para autenticação do usuário, você usará um e-mail e uma senha. Isso significa que a tabela de usuários deve conter um campo de e-mail e senha. No prompt de comando do psql, crie um novo banco de dados chamado nodeapp:
CREATE DATABASE nodeapp;
Em seguida, crie uma tabela para armazenar os usuários:
CREATE TABLE users (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email CHAR(128),
password CHAR(60)
);
Esse código criará uma nova tabela contendo e-mail, senha e um campo de ID gerado automaticamente.
Criando um servidor de nós
Node.js é um ambiente de tempo de execução JavaScript do lado do servidor que nos permite criar servidores HTTP rapidamente. Para simplificar o processo de criação do servidor e diferentes rotas HTTP, você pode usar o Express, um framework web Node.js.
Execute este comando para criar uma nova pasta chamada postgres-auth:
mkdir postgres-auth
Em seguida, inicialize o npm:
npm init -y
Por fim, instale o Express:
npm install express
Agora você pode criar o servidor web Node.
Em um novo arquivo chamado index.jsadicione o seguinte:
const express = require("express");
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.listen(3000, () => console.log("Listening on port 3000"));
A execução deste código iniciará o servidor e registrará o seguinte no console:
Listening on port 3000
Conectando-se ao PostgreSQL
Para se conectar ao PostgreSQL use node-postgres. node-postgres é um driver de conexão que fornece uma interface entre o Node e o Postgres.
Execute o seguinte para instalar o node-postrges via npm:
npm install pg
Depois de instalar essa biblioteca, crie um novo arquivo chamado db.js e conecte-o ao banco de dados:
const { Client } = require("pg");
const { user, host, database, password, port } = require("./dbConfig");const client = new Client({
user,
host,
database,
password,
port,
});
client.connect();
module.exports = client;
O método client do node-postgres pega os detalhes do banco de dados ao qual você está se conectando. Este programa importa seus detalhes de conexão de um arquivo chamado dbConfig. Portanto, crie esse arquivo e adicione o seguinte código a ele:
module.exports = {
user: "postgres",
host: "localhost",
database: "nodeapp",
password: "yourPassword",
port: 5432,
};
Criar funções auxiliares de banco de dados
É sempre uma boa prática usar funções individuais para interagir com o banco de dados. Eles facilitam a escrita de testes de unidade e melhoram a reutilização. Para o endpoint de inscrição, você precisa criar duas funções:
- Para verificar se o e-mail já está cadastrado.
- Para criar o usuário.
O objetivo é registrar um usuário apenas se ele não existir no banco de dados.
Crie um novo arquivo chamado helper.js e importe o cliente de banco de dados do db.js:
const client = require("./db.js")
Em seguida, adicione uma nova função chamada emailExists():
const emailExists = async (email) => {
const data = await client.query("SELECT * FROM users WHERE email=$1", [
email,
]);if (data.rowCount == 0) return false;
return data.rows[0];
};
Esta função recebe um e-mail e verifica se já está em uso. Ele faz isso usando a cláusula SELECT que retorna uma linha que possui um campo de email que corresponde ao valor fornecido pelo usuário registrador. Se o e-mail não existir, ele retornará false.
Para criar uma função que cria o usuário, adicione uma função chamada createUser() ao helper.js:
const createUser = async (email, password) => {
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);const data = await client.query(
"INSERT INTO users(email, password) VALUES ($1, $2) RETURNING id, email, password",
[email, hash]
);
if (data.rowCount == 0) return false;
return data.rows[0];
};
Esta função recebe os valores de email e senha. Ele usa a cláusula INSERT para criar uma nova linha com esses detalhes e, se for bem-sucedida, retorna o usuário recém-criado. Observe que antes de armazenar a senha, você deve fazer o hash usando bcrypt. Nunca é uma boa ideia armazenar senhas como texto simples. Se os hackers tivessem acesso ao seu banco de dados de usuários, eles poderiam acessar facilmente informações confidenciais.
Instale bcryptjs para começar a usá-lo:
npm install bcryptjs
Em helper.js, importe bcryptjs:
const bcrypt = require("bcryptjs")
Ao usar o Bcryptjs, o banco de dados armazena apenas a senha criptografada. Portanto, durante o login, você precisará comparar a senha de texto simples fornecida pelo usuário e a senha com hash no banco de dados. Para isso, você pode usar o método de comparação fornecido pelo Bcryptjs.
Crie uma função chamada matchPassword():
const matchPassword = async (password, hashPassword) => {
const match = await bcrypt.compare(password, hashPassword);
return match
};
Ele recebe a senha simples e o hash e então usa Bcrypt.compare() para determinar se a senha fornecida está correta. Se for, retorna true, caso contrário, retorna false.
Estas são todas as funções que usaremos para interagir com o banco de dados. Certifique-se de exportar todos eles no final:
module.exports = { emailExists, createUser, matchPassword };
Configurar passaporte
O Passport é um middleware de autenticação Node que fornece mais de 500 estratégias de autenticação, como login social, JSON Web Tokens (JWT) e autenticação de e-mail. Estaremos usando o último que a estratégia local do passaporte fornece.
Use o seguinte comando para instalar o passaporte e o passaporte-local:
npm install passport
npm install passport-local
Em seguida, configure o Passport para fazer login de usuários existentes e registrar novos usuários.
Comece criando um novo arquivo passaporteConfig.js. Em seguida, importe a estratégia local do Passport e as funções auxiliares do banco de dados que você acabou de criar:
const LocalStrategy = require("passport-local");
const { emailExists, createUser, matchPassword } = require("./helper");
No mesmo arquivo, adicione o seguinte para configurar a inscrição do usuário:
module.exports = (passport) => {
passport.use(
"local-signup",
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const userExists = await emailExists(email)if (userExists) {
return done(null, false);
}
const user = await createUser(email, password);
return done(null, user);
} catch (error) {
done(error);
}
}
)
);
}
Como o passaporte-local espera um nome de usuário e uma senha e você está usando um e-mail, defina o campo de nome de usuário como um e-mail. O usuário, ou melhor, a parte frontend deste aplicativo enviará o e-mail e a senha no corpo da solicitação. No entanto, você não precisa extrair os valores sozinho, pois o Passport lidará com isso em segundo plano.
Este programa primeiro verifica se o email já foi recebido usando a função emailExists() do helper.js. Se o email não existir no banco de dados, ele cria um novo usuário com a função createUser(). Por fim, ele retorna o objeto do usuário.
Para fazer login de usuários, adicione o seguinte ao passaporteConfig.js:
module.exports = (passport) => {
passport.use(
"local-signup",
new LocalStrategy(
)
);
passport.use(
"local-login",
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await emailExists(email);
if (!user) return done(null, false);
const isMatch = await matchPassword(password, user.password);
if (!isMatch) return done(null, false);
return done(null, {id: user.id, email: user.email});
} catch (error) {
return done(error, false);
}
}
)
);
};
Aqui, o programa primeiro verifica se o e-mail está registrado. Se não, ele retorna falso. Se encontrar o e-mail, ele compara sua senha com a da solicitação. Se as senhas corresponderem, ele efetuará login no usuário e retornará o objeto de usuário.
A etapa final é criar os endpoints da API:
- POST /auth/signup
- POST /auth/login
Ambos os endpoints receberão um e-mail e senha no corpo da solicitação. Eles também incluirão as funções de middleware de autenticação de passaporte que acabamos de configurar.
Importe e configure o Passport em um novo arquivo chamado server.js:
const passport = require("passport");
require("./passportConfig")(passport);
Em seguida, adicione as seguintes rotas:
app.post(
"/auth/signup",
passport.authenticate("local-signup", { session: false }),
(req, res, next) => {
res.json({
user: req.user,
});
}
);
app.post(
"/auth/login",
passport.authenticate("local-login", { session: false }),
(req, res, next) => {
res.json({ user: req.user });
}
);
Ambas as rotas retornam um objeto JSON contendo o usuário se forem bem-sucedidas.
Verifique sua API usando testes de unidade
Você pode usar o Passport para autenticar um aplicativo Node usando um aplicativo PostgreSQL. Você criou endpoints de API para inscrever e fazer login de usuários.
Embora você possa usar clientes REST como o Postman para testar o funcionamento de uma API, escrever testes de unidade é muito mais simples. Os testes de unidade permitem que você teste as partes individuais de seu aplicativo. Dessa forma, mesmo que um endpoint falhe, você pode identificar o ponto exato da falha. Uma das ferramentas que você pode usar para testar aplicativos Node é o Jest.