Nesta aula, vamos aprender a implementar autenticação básica sem o uso de bibliotecas externas para autenticação. Isso inclui:

  1. Criação de Usuário com Senha Hashed
  2. Autenticação de Login
  3. Gerenciamento de Sessões de Usuários

A senha será armazenada no banco de dados de forma segura utilizando hashing, e vamos criar uma simples sessão em memória para manter o estado de login dos usuários.

Passos para Implementação

1. Alteração no Model de Usuário (models/userModel.ts)

Vamos adicionar um campo para armazenar o hash da senha do usuário:

export interface User {
  id: number;
  name: string;
  email: string;
  passwordHash: string; // Armazenar o hash da senha
}

2. Atualizando o Repositório de Usuários (repositories/userRepository.ts)

O repositório agora deve permitir adicionar o passwordHash durante a criação de um novo usuário:

import { Pool } from 'pg';
import pool from '../config/database';
import { User } from '../models/userModel';

export class UserRepository {
  private pool: Pool;

  constructor() {
    this.pool = pool;
  }

  // Método para buscar usuário pelo email
  async getUserByEmail(email: string): Promise<User | null> {
    const { rows } = await this.pool.query('SELECT * FROM users WHERE email = $1', [email]);
    return rows[0] || null;
  }

  // Método para adicionar um novo usuário com senha hashed
  async addUser(name: string, email: string, passwordHash: string): Promise<User> {
    const queryText = 'INSERT INTO users(name, email, passwordHash) VALUES($1, $2, $3) RETURNING *';
    const { rows } = await this.pool.query(queryText, [name, email, passwordHash]);
    return rows[0];
  }
}

3. Função para Gerar o Hash da Senha (helpers/hashHelper.ts)

Vamos usar o módulo nativo crypto do Node.js para criar o hash da senha:

import crypto from 'crypto';

export const hashPassword = (password: string): string => {
  return crypto.createHash('sha256').update(password).digest('hex');
};

export const comparePassword = (password: string, hash: string): boolean => {
  return hashPassword(password) === hash;
};

4. Gerenciamento de Sessões Simples

Criaremos uma estrutura em memória para manter o estado de login dos usuários (sessão simples). Isso será armazenado como um objeto, onde a chave é o ID do usuário e o valor é true se o usuário estiver logado.

// Simples armazenamento de sessão
const sessions: { [key: number]: boolean } = {};

export const createSession = (userId: number) => {
  sessions[userId] = true;
};

export const destroySession = (userId: number) => {
  delete sessions[userId];
};

export const isUserLoggedIn = (userId: number): boolean => {
  return !!sessions[userId];
};

5. Serviço de Autenticação (services/authService.ts)

Agora, criaremos um serviço de autenticação que gerencia a criação de usuários e o login.