Sistema de Login

Conceitos que serão ensinados:

  • password_hash() — criptografa senha

  • password_verify() — verifica senha

  • Sessões PHP ($_SESSION)

  • header('Location: ...') — redirecionamento

  • Nunca salvar senha em texto puro!


1 Script do banco — banco.sql

CREATE DATABASE IF NOT EXISTS auth_system
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE auth_system;

CREATE TABLE IF NOT EXISTS usuarios (
    id INT AUTO_INCREMENT PRIMARY KEY,
    nome VARCHAR(150) NOT NULL,
    email VARCHAR(150) UNIQUE NOT NULL,
    senha VARCHAR(255) NOT NULL,
    nivel ENUM('admin', 'usuario') DEFAULT 'usuario',
    ativo TINYINT(1) DEFAULT 1,
    data_cadastro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- IMPORTANTE: insira os usuários via cadastro.php para gerar o hash correto
-- Não insira senhas em texto puro!

2 Arquivo config.php

<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', '');
define('DB_NAME', 'auth_system');

$conexao = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);

if ($conexao->connect_error) {
    die("Erro: " . $conexao->connect_error);
}
$conexao->set_charset('utf8mb4');

if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

function estaLogado() {
    return isset($_SESSION['usuario_id']);
}

function exigirLogin() {
    if (!estaLogado()) {
        header('Location: login.php');
        exit;
    }
}

function usuarioLogado($conexao) {
    if (!estaLogado()) return null;
    $stmt = $conexao->prepare("SELECT id, nome, email, nivel FROM usuarios WHERE id = ?");
    $stmt->bind_param('i', $_SESSION['usuario_id']);
    $stmt->execute();
    $user = $stmt->get_result()->fetch_assoc();
    $stmt->close();
    return $user;
}
?>

3 Arquivo cadastro.php

<?php
require_once 'config.php';

$erros = [];
$sucesso = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $nome = trim($_POST['nome'] ?? '');
    $email = trim($_POST['email'] ?? '');
    $senha = $_POST['senha'] ?? '';

    // Validações
    if (strlen($nome) < 3) $erros[] = 'Nome muito curto';
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $erros[] = 'E-mail inválido';
    if (strlen($senha) < 6) $erros[] = 'Senha deve ter pelo menos 6 caracteres';

    // Verifica se e-mail já existe
    if (empty($erros)) {
        $stmt = $conexao->prepare("SELECT id FROM usuarios WHERE email = ?");
        $stmt->bind_param('s', $email);
        $stmt->execute();
        if ($stmt->get_result()->num_rows > 0) {
            $erros[] = 'E-mail já cadastrado';
        }
        $stmt->close();
    }

    // Cadastra
    if (empty($erros)) {
        $hash = password_hash($senha, PASSWORD_DEFAULT);

        $stmt = $conexao->prepare(
            "INSERT INTO usuarios (nome, email, senha) VALUES (?, ?, ?)"
        );
        $stmt->bind_param('sss', $nome, $email, $hash);

        if ($stmt->execute()) {
            $sucesso = 'Cadastro realizado com sucesso! Faça login.';
        } else {
            $erros[] = 'Erro ao cadastrar';
        }
        $stmt->close();
    }
}
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Cadastro</title>
    <link rel="stylesheet" href="style.css">
</head>
<body class="auth-body">
    <div class="auth-card">
        <div class="auth-icon">📝</div>
        <h1>Criar Conta</h1>
        <p class="auth-sub">Preencha os dados para se cadastrar</p>

        <?php if (!empty($erros)): ?>
            <div class="alert alert-error">
                <?php foreach ($erros as $e): ?>
                    <div>⚠️ <?php echo htmlspecialchars($e); ?></div>
                <?php endforeach; ?>
            </div>
        <?php endif; ?>

        <?php if ($sucesso): ?>
            <div class="alert alert-success">✅ <?php echo $sucesso; ?></div>
        <?php endif; ?>

        <form method="POST">
            <div class="form-group">
                <label>Nome completo</label>
                <input type="text" name="nome" required 
                       value="<?php echo htmlspecialchars($_POST['nome'] ?? ''); ?>">
            </div>
            <div class="form-group">
                <label>E-mail</label>
                <input type="email" name="email" required
                       value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>">
            </div>
            <div class="form-group">
                <label>Senha</label>
                <input type="password" name="senha" required minlength="6">
            </div>
            <button type="submit" class="btn-full">Cadastrar</button>
        </form>

        <p class="auth-footer">
            Já tem conta? <a href="login.php">Faça login</a>
        </p>
    </div>
</body>
</html>

4 Arquivo login.php

<?php
require_once 'config.php';

if (estaLogado()) {
    header('Location: painel.php');
    exit;
}

$erro = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email = trim($_POST['email'] ?? '');
    $senha = $_POST['senha'] ?? '';

    if (empty($email) || empty($senha)) {
        $erro = 'Preencha todos os campos';
    } else {
        $stmt = $conexao->prepare(
            "SELECT id, nome, senha, ativo FROM usuarios WHERE email = ?"
        );
        $stmt->bind_param('s', $email);
        $stmt->execute();
        $usuario = $stmt->get_result()->fetch_assoc();
        $stmt->close();

        if ($usuario && password_verify($senha, $usuario['senha'])) {
            if (!$usuario['ativo']) {
                $erro = 'Conta desativada';
            } else {
                $_SESSION['usuario_id'] = $usuario['id'];
                $_SESSION['usuario_nome'] = $usuario['nome'];
                header('Location: painel.php');
                exit;
            }
        } else {
            $erro = 'E-mail ou senha incorretos';
        }
    }
}
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Login</title>
    <link rel="stylesheet" href="style.css">
</head>
<body class="auth-body">
    <div class="auth-card">
        <div class="auth-icon">🔒</div>
        <h1>Entrar</h1>
        <p class="auth-sub">Acesse sua conta</p>

        <?php if ($erro): ?>
            <div class="alert alert-error">⚠️ <?php echo htmlspecialchars($erro); ?></div>
        <?php endif; ?>

        <form method="POST">
            <div class="form-group">
                <label>E-mail</label>
                <input type="email" name="email" required autofocus
                       value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>">
            </div>
            <div class="form-group">
                <label>Senha</label>
                <input type="password" name="senha" required>
            </div>
            <button type="submit" class="btn-full">Entrar</button>
        </form>

        <p class="auth-footer">
            Não tem conta? <a href="cadastro.php">Cadastre-se</a>
        </p>
    </div>
</body>
</html>

5 Arquivo painel.php

<?php
require_once 'config.php';
exigirLogin();

$usuario = usuarioLogado($conexao);
?>
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Painel</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <div class="painel-card">
            <div class="user-avatar">
                <?php echo strtoupper(substr($usuario['nome'], 0, 1)); ?>
            </div>
            <h1>Olá, <?php echo htmlspecialchars($usuario['nome']); ?>!</h1>
            <p class="user-email">📧 <?php echo htmlspecialchars($usuario['email']); ?></p>
            <p class="user-nivel">
                Nível: <strong><?php echo $usuario['nivel']; ?></strong>
            </p>

            <div class="painel-actions">
                <a href="logout.php" class="btn-logout">🚪 Sair</a>
            </div>
        </div>
    </div>
</body>
</html>

6 Arquivo logout.php

<?php
session_start();
session_destroy();
header('Location: login.php');
exit;
?>

7 Arquivo style.css

/* style.css - Sistema de Login */

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: 'Segoe UI', sans-serif;
    background: linear-gradient(135deg, #1e3a8a 0%, #312e81 100%);
    min-height: 100vh;
    color: #1f2937;
}

/* Auth */
body.auth-body {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

.auth-card {
    background: white;
    padding: 45px 35px;
    border-radius: 16px;
    width: 100%;
    max-width: 420px;
    box-shadow: 0 25px 60px rgba(0,0,0,0.4);
    border-top: 4px solid #fbbf24;
    text-align: center;
}

.auth-icon {
    font-size: 3rem;
    margin-bottom: 15px;
}

.auth-card h1 {
    color: #1e3a8a;
    font-size: 1.6rem;
    margin-bottom: 6px;
}

.auth-sub {
    color: #6b7280;
    font-size: 0.9rem;
    margin-bottom: 25px;
}

.form-group {
    display: flex;
    flex-direction: column;
    margin-bottom: 18px;
    text-align: left;
}

.form-group label {
    font-size: 0.82rem;
    font-weight: 600;
    color: #1e3a8a;
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.form-group input {
    padding: 13px 16px;
    border: 2px solid #e5e7eb;
    border-radius: 8px;
    font-size: 1rem;
    font-family: inherit;
    transition: all 0.2s;
}

.form-group input:focus {
    outline: none;
    border-color: #1e3a8a;
    box-shadow: 0 0 0 3px rgba(30, 58, 138, 0.1);
}

.btn-full {
    width: 100%;
    padding: 14px;
    background: #1e3a8a;
    color: white;
    border: none;
    border-radius: 8px;
    font-size: 0.95rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    cursor: pointer;
    font-family: inherit;
    transition: all 0.2s;
    margin-top: 10px;
}

.btn-full:hover {
    background: #1e40af;
    transform: translateY(-2px);
    box-shadow: 0 8px 20px rgba(30, 58, 138, 0.3);
}

.auth-footer {
    margin-top: 20px;
    color: #6b7280;
    font-size: 0.9rem;
}

.auth-footer a {
    color: #1e3a8a;
    font-weight: 600;
    text-decoration: none;
}

.auth-footer a:hover {
    text-decoration: underline;
}

/* Alertas */
.alert {
    padding: 12px 16px;
    border-radius: 8px;
    margin-bottom: 20px;
    text-align: left;
    font-size: 0.9rem;
    line-height: 1.6;
}

.alert-error {
    background: #fee2e2;
    color: #991b1b;
    border-left: 4px solid #ef4444;
}

.alert-success {
    background: #d1fae5;
    color: #065f46;
    border-left: 4px solid #10b981;
}

/* Painel */
.container {
    max-width: 600px;
    margin: 0 auto;
    padding: 60px 20px;
}

.painel-card {
    background: white;
    padding: 50px 40px;
    border-radius: 16px;
    text-align: center;
    box-shadow: 0 25px 60px rgba(0,0,0,0.3);
}

.user-avatar {
    width: 90px;
    height: 90px;
    background: linear-gradient(135deg, #1e3a8a, #312e81);
    color: #fbbf24;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.5rem;
    font-weight: 800;
    margin: 0 auto 20px;
}

.painel-card h1 {
    color: #1e3a8a;
    margin-bottom: 10px;
}

.user-email {
    color: #6b7280;
    margin-bottom: 8px;
}

.user-nivel {
    color: #6b7280;
    margin-bottom: 25px;
}

.btn-logout {
    display: inline-block;
    padding: 12px 30px;
    background: #ef4444;
    color: white;
    text-decoration: none;
    border-radius: 8px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    font-size: 0.85rem;
    transition: all 0.2s;
}

.btn-logout:hover {
    background: #dc2626;
    transform: translateY(-2px);
}

8-index.php

<?php
// index.php - Redireciona para a página de login
require_once 'config.php';

if (estaLogado()) {
    header('Location: painel.php');
} else {
    header('Location: login.php');
}
exit;
?>