Projeto: sistema de login
LidoNesta aula, você construirá um sistema de login completo em PHP, abordando cadastro de usuários, hash seguro de senhas, gerenciamento de sessões e proteção de rotas. Ao final, você terá um projeto funcional com boas práticas de segurança.
Nesta aula, vamos construir um sistema de login completo em PHP, do zero. Você aprenderá na prática como implementar o cadastro de usuários, armazenar senhas de forma segura com hash, gerenciar sessões e proteger rotas que exigem autenticação. Este projeto serve como base para qualquer aplicação web que precise de controle de acesso.
Vamos utilizar PHP orientado a objetos e PDO para acesso a banco de dados, garantindo código limpo e seguro. Ao final, você terá um sistema funcional que pode ser expandido com funcionalidades como recuperação de senha, perfis e níveis de acesso.
Cadastro
O cadastro é a primeira etapa do sistema. Precisamos criar um formulário que receba nome, e-mail e senha, e armazene esses dados no banco de dados. É fundamental validar os dados no servidor para evitar problemas como e-mails duplicados ou senhas fracas.
Vamos criar uma tabela users com os campos: id, name, email, password, e created_at. O campo email deve ser único para evitar duplicidades. No script de cadastro, verificamos se o e-mail já existe antes de inserir.
Exemplo de código para processar o cadastro:
prepare("SELECT id FROM users WHERE email = ?");
$stmt->execute([$email]);
if ($stmt->fetch()) {
$erro = "Este e-mail já está cadastrado.";
} else {
// Hash da senha (veremos na próxima seção)
$hash = password_hash($senha, PASSWORD_DEFAULT);
// Insere no banco
$stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
$stmt->execute([$nome, $email, $hash]);
// Redireciona para login
header('Location: login.php?cadastro=sucesso');
exit;
}
}
}
?>
Cadastro
Hash de senha
Armazenar senhas em texto puro é um erro gravíssimo de segurança. Se o banco de dados for comprometido, todas as senhas ficam expostas. Por isso, utilizamos funções de hash, que transformam a senha em uma sequência de caracteres irreversível. O PHP oferece a função password_hash() que gera um hash seguro usando o algoritmo bcrypt (ou mais forte, se disponível).
Para verificar a senha no login, usamos password_verify(), que compara a senha fornecida com o hash armazenado. Nunca tente reverter o hash; a verificação é feita internamente pela função.
Exemplo de hash e verificação:
É importante notar que o hash gerado é único mesmo para a mesma senha, devido ao salt aleatório. Isso dificulta ataques de força bruta e tabelas rainbow.
Sessão
Sessões permitem manter o estado do usuário entre requisições HTTP, que são stateless. Após o login, armazenamos informações do usuário na variável superglobal $_SESSION. O PHP inicia a sessão com session_start() e a mantém através de um cookie de sessão.
No login, após verificar as credenciais, definimos variáveis de sessão como $_SESSION['user_id'] e $_SESSION['user_name']. Para encerrar a sessão (logout), usamos session_destroy() e session_unset().
Exemplo de login com sessão:
prepare("SELECT * FROM users WHERE email = ?");
$stmt->execute([$email]);
$user = $stmt->fetch();
if ($user && password_verify($senha, $user['password'])) {
// Regenera o ID da sessão para evitar fixação
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['name'];
header('Location: painel.php');
exit;
} else {
$erro = "Credenciais inválidas.";
}
}
?>É recomendável chamar session_regenerate_id() após o login para prevenir ataques de fixação de sessão.
Proteção de rotas
Proteger rotas significa impedir que usuários não autenticados acessem páginas restritas. A técnica mais simples é verificar se a variável de sessão user_id existe no início de cada página protegida. Se não existir, redirecionamos para a página de login.
Podemos criar um arquivo auth.php que é incluído no topo de cada página protegida. Esse arquivo verifica a sessão e redireciona se necessário.
Exemplo de proteção:
Então, em painel.php, incluímos:
Painel
Bem-vindo, !
Sair
Além disso, podemos usar um roteador (como o do MVC) para centralizar a proteção, mas para este projeto, a inclusão simples é suficiente.
Boas práticas e observações finais
Ao construir sistemas de login, sempre utilize HTTPS em produção para proteger os dados em trânsito. Use htmlspecialchars() ao exibir dados do usuário para evitar XSS. Mantenha as senhas com hash e nunca as envie por e-mail. Considere implementar proteção contra CSRF em formulários e limitar tentativas de login para evitar força bruta.
Este projeto é a base para sistemas mais complexos. Você pode adicionar recuperação de senha, confirmação de e-mail, níveis de acesso e integração com redes sociais.
Referências
- PHP: Password Hashing
- PHP: $_SESSION
- PHP: session_start
- PHP: session_regenerate_id
- PHP: password_verify
- PHP: Prepared Statements
- MDN: Set-Cookie
Exercícios
- Exercício 1: Crie um script PHP que receba um e-mail e senha via POST, e verifique se a senha tem pelo menos 8 caracteres. Se não tiver, exiba uma mensagem de erro. Caso contrário, exiba "Válido".
- Exercício 2: Escreva um código que gere um hash para a senha "123456" usando
password_hashe depois verifique se a senha "123456" corresponde ao hash. Exiba o resultado. - Exercício 3: Crie um script que inicia uma sessão e define as variáveis
nomeelogado(valor true). Em seguida, exiba o nome da sessão. - Exercício 4: Crie um arquivo
protegido.phpque verifica se a sessão está ativa (variáveluser_idexiste). Se não estiver, redirecione paralogin.php. - Exercício 5: Implemente um logout simples que destrói a sessão e redireciona para a página de login.