Título: Avaliação Final - Fundamentos em Nuvem
Seu Nome Completo: Caio Eduardo Ferreira Frederico
Nome do Projeto: Sistema de Cadastro e Login com Node.js e MySQL
Este documento apresenta a implementação de um sistema básico de cadastro e login de usuários, desenvolvido como parte da avaliação final de Fundamentos em Nuvem. O projeto utiliza Node.js para o backend, Express como framework web, MySQL para o banco de dados e interfaces HTML/CSS/JavaScript no frontend. As senhas dos usuários são armazenadas de forma segura utilizando hash com bcrypt.
- Introdução
- Seção 1: Projeto e Planejamento
- Seção 2: Implementação do Sistema
- Seção 3: Demonstração do Sistema
- Conclusão
Manual do Usuário - Sistema de Cadastro e Login
Este manual fornece instruções passo a passo para utilizar o sistema de cadastro e login.
1. Acesso ao Sistema:
- Página de Cadastro: Abra seu navegador e acesse
http://localhost:3000/register.html - Página de Login: Abra seu navegador e acesse
http://localhost:3000/login.html
2. Como Cadastrar um Novo Usuário:
- Acesse a página de cadastro (
http://localhost:3000/register.html). - Preencha o campo "Nome de Usuário" com o nome desejado.
- Preencha o campo "Email" com um endereço de e-mail válido e que ainda não esteja cadastrado.
- Preencha o campo "Senha" com uma senha segura.
- Clique no botão "Cadastrar".
- Uma mensagem de sucesso ou erro aparecerá abaixo do formulário. Se o cadastro for bem-sucedido, a mensagem será verde e o formulário será limpo.
3. Como Fazer Login:
- Acesse a página de login (
http://localhost:3000/login.html). - Preencha o campo "Email" com o e-mail de um usuário já cadastrado.
- Preencha o campo "Senha" com a senha correspondente.
- Clique no botão "Entrar".
- Uma mensagem de sucesso ou erro aparecerá abaixo do formulário. Se o login for bem-sucedido, a mensagem será verde.
O código-fonte completo do projeto, incluindo o frontend (HTML, CSS, JavaScript), o backend (Node.js/Express) e as configurações de banco de dados, está versionado no GitHub.
Link para o Repositório GitHub: Sistema Auth
Estrutura do Banco de Dados (Script SQL): As tabelas
userseprofilesforam criadas no MySQL com base no seguinte script SQL:-- Criar o banco de dados (se ainda não existir) CREATE DATABASE IF NOT EXISTS nodejs_auth_db;-- Usar o banco de dados recém-criado
USE nodejs_auth_db;-- Tabela de usuários (users)
CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE, telefone VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );-- Tabela de perfis (profiles)
CREATE TABLE IF NOT EXISTS profiles ( user_id INT PRIMARY KEY, data_nascimento DATE, foto_perfil VARCHAR(255), FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );
Código Frontend (public/register.html - Trecho principal do formulário e script):
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cadastro de Usuário</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="containier">
<h2>Cadastro de Usuários</h2>
<form id="registerForm">
<div class="input-group">
<label for="registerUsername">Nome de Usuário:</label>
<input type="text" id="registerUsername" name="username" required>
</div>
<div class="input-group">
<label for="registerEmail">Email:</label>
<input type="email" id="registerEmail" name="email" required>
</div>
<div class="input-group">
<label for="registerPassword">Senha:</label>
<input type="password" id="registerPassword" name="password" required>
</div>
<button type="submit">Cadastrar</button>
</form>
<p>Já tem uma conta? <a href="login.html">Faça login aqui</a></p>
<p id="registerMessage" class="message"></p>
</div>
<script>
document.getElementById('registerForm').addEventListener('submit', async (event) => {
event.preventDefault(); // Impede o envio padrão do formulário
const username = document.getElementById('registerUsername').value;
const email = document.getElementById('registerEmail').value;
const password = document.getElementById('registerPassword').value;
const messageElement = document.getElementById('registerMessage');
try {
const response = await fetch('/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, email, password })
});
const data = await response.json();
if (response.ok) {
messageElement.textContent = data.message;
messageElement.style.color = 'green';
document.getElementById('registerForm').reset(); // Limpa o formulário
} else {
messageElement.textContent = `Erro: ${data.message}`;
messageElement.style.color = 'red';
}
} catch (error) {
console.error('Erro ao enviar requisição de registro:', error);
messageElement.textContent = 'Erro ao conectar com o servidor.';
messageElement.style.color = 'red';
}
});
</script>
</body>
</html>Código Backend (server.js - Trecho da rota /register):
app.post('/register', async (req, res) => {
// Extrai username, email e password do corpo da requisição
const { username, email, password } = req.body;
// Valiidação básiica de entrada
if (!username || !email || !password) {
return res.status(400).json({ message: 'Todos os campos obrigatórios (username, email, password) devem ser preenchidos.'});
}
let connection;
try {
connection = await pool.getConnection(); // Obtém uma conexão do pool
// 1. Verificar se o usuário ou e-mail já existem
const [existingUsers] = await connection.execute(
'SELECT id FROM users WHERE username = ? OR email = ?',
[username, email]
);
if (existingUsers.length > 0) {
return res.status(409).json({ message: 'Nome de usuário ou e-mail já cadastro.'});
}
// 2. Gerar hash da senha para segurança
const saltRounds = 10; // Custo de processamento para o hash (Quanto maios, mais seguro, porém mais lento)
const hashedPassword = await bcrypt.hash(password, saltRounds);
// 3. Inserir o novo usuário na tabela 'users'
const [result] = await connection.execute(
'INSERT INTO users (username, email, password) VALUES (?, ?, ?)',
[username, email, hashedPassword]
);
// 4. Inserir um registro vazio na tabela 'profiles' para o novo usuário
// A chave estrangeira user_id será o ID do usuário recém-criado
await connection.execute(
'INSERT INTO profiles (user_id) VALUES (?)',
[result.insertId] // insertId contem o ID do último registro inserido
);
res.status(201).json({ message: 'Usuário registrado com sucesso!', userId: result.insertId });
} catch(error) {
console.error('Erro no registro:', error);
res.status(500).json({ message: 'Erro interno no servidor ao registrar usuário.'});
} finally {
if (connection) connection.release() // Libera a conexão de volta para a pool
}
});Explicação: A página register.html exibe um formulário para o usuário inserir nome de usuário, e-mail e senha. O JavaScript no frontend captura esses dados e os envia via fetch (método POST) para a rota /register no backend. No server.js, esta rota recebe os dados, valida-os, verifica se o e-mail ou nome de usuário já existem, gera um hash seguro da senha usando bcrypt e, finalmente, insere as informações do novo usuário (incluindo o hash da senha) nas tabelas users e profiles do MySQL.
Código Frontend (public/login.html - Trecho principal do formulário e script):
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login de Usuário</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h2>Login de Usuário</h2>
<form id="loginForm">
<div class="input-group">
<label for="loginEmail">Email:</label>
<input type="email" id="loginEmail" name="email" required>
</div>
<div class="input-group">
<label for="loginPassword">Senha:</label>
<input type="password" id="loginPassword" name="password" required>
</div>
<button type="submit">Entrar</button>
</form>
<p>Não tem uma conta? <a href="register.html">Cadastre-se aqui</a></p>
<p id="loginMessage" class="message"></p>
</div>
<script>
document.getElementById('loginForm').addEventListener('submit', async (event) => {
event.preventDefault(); // Impede o envio padrão do formulário
const email = document.getElementById('loginEmail').value;
const password = document.getElementById('loginPassword').value;
const messageElement = document.getElementById('loginMessage');
try {
const response = await fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (response.ok) {
messageElement.textContent = data.message;
messageElement.style.color = 'green';
} else {
messageElement.textContent = `Erro: ${data.message}`;
messageElement.style.color = 'red';
}
} catch (error) {
console.error('Error ao enviar requisição de login:', error);
messageElement.textContent = 'Erro ao conectar com o servidor.';
messageElement.style.color = 'red';
}
});
</script>
</body>
</html>Código Backend (server.js - Trecho da rota /login):
app.post('/login', async (req, res) => {
const { email, password } = req.body;
// Validação básica de entrada
if (!email || !password) {
return res.status(400).json({ message: 'E-mail e senhha são obrigatórios.'});
}
let connection;
try {
connection = await pool.getConnection(); // Obtém uma conexão pool
// 1. Buscar o usuário pelo e-mail
const [users] = await connection.execute(
'SELECT id, username, password FROM users WHERE email = ?',
[email]
);
// Se nenhum usuário for encontrado com o e-mail
if (users.length == 0) {
return res.status(401).json({ message: 'Credenciais inválidas.' });
}
const user = users[0];
// 2. Comparar a senha fornecida com o hash armazenado
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: 'Credenciais inválidas' });
}
// Se as credenciais estiverem corretas
res.status(200).json({ message: 'Login realizado com sucesso!', userId: user.id, username: user.username });
} catch (error) {
console.error('Erro no login:', error);
res.status(500).json({ message: 'Erro interno do servidor ao fazer login' });
} finally {
if (connection) connection.release(); // Libera a conexão de volta para o pool
}
});Explicação: A página login.html apresenta um formulário para que o usuário insira seu e-mail e senha. O JavaScript captura esses valores e os envia via fetch (método POST) para a rota /login no backend. No server.js, essa rota busca o usuário pelo e-mail no banco de dados e, em seguida, usa bcrypt.compare para verificar se a senha fornecida corresponde ao hash armazenado. Se as credenciais estiverem corretas, uma mensagem de sucesso é retornada.
Este projeto permitiu aplicar conhecimentos em desenvolvimento web full-stack, desde a configuração do ambiente, modelagem de banco de dados, desenvolvimento de APIs REST com Node.js e Express, até a criação de interfaces de usuário com HTML, CSS e JavaScript. A implementação da segurança de senhas com
bcryptreforça a importância das boas práticas em desenvolvimento de software.
Você pode encontrar esse README no formato de PDF aqui.

