# Aula 8 Hoje vamos passar a utilizar um framework para facilitar nossa vida em diversos aspectos quando estivermos criando nosso back-end. Para isso, vamos usar o Express. Passamos por várias etapas até chegar aqui, entendemos mais como o node funciona por trás, entendemos como funciona um webserver assim como fazemos requisições para o externo. Já subimos o nível utilizando o Axios para fazer as requisições e agora vamos utilizar o Express para ser nossa escolha para lidar com as requisições que chegam até nosso servidor. Como dito, já sabemos montar uma estrutura puramente em node que e segue a seguinte estrutura: ```typescript const http = require('http'); const server = http.createServer((req, res) => { if (req.url === "/") { res.writeHead(200); res.write('This is a pure node webserver!'); res.end(); } }); server.listen(8081); ``` Já se formos para o Express, temos: ```typescript const express = require('express'); const server = express(); server.get('/', (req, res) => { res.status(200); return res.send('This is a pure express webserver'); }); server.listen(8081); ``` Parece bem parecido né? Mas ao longo do tempo vamos ver várias mudanças. Nossa proposta hoje é de lidarmos com autenticação de um usuário. Então, vamos criar todo o contexto para que exista Login, certo? Então, vamos decidir uma estrutura de dados para nossos usuários: ```typescript [ { name: 'José', username: 'josejose', email: 'jose@jose.com', password: '123456', }, { name: 'Nícolas', username: 'nini_colas', email: 'nicolas@nicolas.com', password: '654321'', }, { name: 'Joshua', username: 'joshinho_2009', email: 'joshua@joshua.com', password: 'lambda2009', }, { name: 'Fernanda', username: 'fe_coracoes', email: 'nanda@nanda.com', password: '102030!', }, ] ``` Vamos fazer as operações para o nosso banco de dados virtual? Temos quatro operações pelo menos na nossa aplicação: - Criar usuário; - Atualizar usuário; - Remover usuário; - Obter usuário(s). Vamos criar um novo usuário: ```typescript let users = []; const createUser = (user) => { const { name, username, email, password } = user; users.push({ name, username, email, password, }); return user; }; ``` Agora, deletar um usuário: ```typescript const users = []; const deleteUser = (index) => { const { name, username, email, password } = user; users = users.filter((usr, idx) => idx !== index); }; ``` Agora, vamos atualizar um usuário: ```typescript const users = []; const updateUser = (index) => { users[index] = { ...users[index], ...user }; const { name, email, username } = users[index]; return { name, email, username }; }; ``` E por último obter tanto apenas um usuário quando todos; ```typescript const users = []; const getUser = (index) => { return users.find((user, idx) => { return idx === index; }); }; const getUsers = () => { return users; }; ``` Vamos então usar o express para fornecer essas operações: ```typescript const express = require('express'); const server = express(); const users = [ { name: 'José', username: 'josejose', email: 'jose@jose.com', password: '123456', }, { name: 'Nícolas', username: 'nini_colas', email: 'nicolas@nicolas.com', password: '654321', }, { name: 'Joshua', username: 'joshinho_2009', email: 'joshua@joshua.com', password: 'lambda2009', }, { name: 'Fernanda', username: 'fe_coracoes', email: 'nanda@nanda.com', password: '102030!', }, ]; server.get('/users', (req, res) => { // // const users = getUsers().map(({ password, ...rest }) => rest); // return res.send(users); return res.send(getUsers()); }); server.get('/users/:id', (req, res) => { const { id } = req.params; // return users.find((user, idx) => idx.toString() === index); return getUser(id); }); server.post('/users', (req, res) => { const { user } = req.body; const usr = createUser(user); return res.send(usr); }); server.delete('/users/:id', (req, res) => { deleteUser(req.params.id); return res.send(); }); server.put('/users/:id', (req, res) => { const user = updateUser(req.params.id, req.body.user); return res.send(user); }); server.listen(8081); ``` A gente já pode pegar cada um desses métodos e colocar em seus devidos lugares; Então, todos esses métodos referente são controllers e a gente pode reescrevê-los da seguinte forma: ```typescript // controllers/userController.js const create = (req, res) => { const { name, username, email, password } = req.body.user; users.push({ name, username, email, password, }); return user; }; const delete = (req, res) => { ... }; const update = (req, res) => { ... }; const get = (req, res) => { ... }; const getAll = (req, res) => { ... }; module.exports = { create, delete, get, getAll, update }; ``` Vamos fazer algo mais interessante também, vamos agora separar um arquivo apenas para as rotas. ```typescript // routes.js const { Router } = require("express"); const userController = require("./controllers/userController"); const routes = new Router(); routes.post('users', userController.create); routes.get('/users', userController.getAll); routes.get('/users/:id', userController.get); routes.put('/users/:id', userController.update); routes.delete('/users/:id', userController.delete); export.modules = routes; ``` Isso tudo deve funcionar. Mas temos um problema de segurança, estamos guardando nossa senha em plain text. Isso não é nenhum pouco seguro. Vamos ver o porquê: Vamos supor que você tem vários usuários User 1 | email1 | 123456 User 2 | email2 | 654321 User 3 | email3 | 123456 Suponho que seu banco de dados seja exposto, um indíviduo vai conseguir utilizar essas informações como quaisquer outras em vários outros sites já que as pessoas costumam repetir as senhas. Em alguns algoritmos, como MD5 por exemplo, você gera um mesmo hash para uma mesma senha. Isso significa que se seu banco de dados for exposto, alguém pode criar um Dictionary Attack, e criar uma tabela em milhões de senhas e hashes e testar em vários casos a senha que seu usuário escolheu. Em outros algoritmos como o BCrypt, por exemplo, você pode escolher um `salt`, um código para ser somado a sua senha e então, você vai gerar uma senha que é condicionada a esse código. No entanto, isso ainda pode falhar, você expor de alguma maneira esse salt, devido ao BCrypt ser um algoritmo que foi feito pra ser lento, a nova tabela de senhas que o individuo irá gerar em para uma pré-computação irá demorar. No entanto, o interessante do bcrypt é que você pode não se preocupar com o salt, e gerar um salt novo a cada nova senha. Então, uma senha nunca será como a outra. Então, vamos implementar o uso do bcrypt utilizando bcrypt.js ```typescript const hash = await bcrypt.hash(req.body.user.password, 10); req.body.user.password = hash; ``` Agora podemos começar a implementar nossa autenticação, a ideia é que teremos algo como: ```typescript { "email": "nicolas@nicolas.com", "password": "102030", } // /auth ``` ```typescript // AuthController.js const jwt = require("jsonwebtoken"); const AuthController = async (req, res) => { const { email, password } = req.body; const user = users.find(usr => usr.email === email); if (!(await bcrypt.compare(password, user.password))) { // Tratar erro; } const { name, username } = user; if (user) { const token = jwt.sign({ email }, "$2y$10$tcDhjxTBRNtZCe.y1beGc.9pHARnfckImiOKqAluVgaXDmzUa5SUi", { expiresIn: '14d' }); return { name, email, username, token, }; } }; ``` Agora a gente vai poder tratar usuários tentando fazer requisições pra gente. Inicialmente vamos barrar qualquer requisição que não estiver autenticada. Então a gente vai entrar com o conceito de middlewares, que são interceptadores das nossas requisições. ```typescript const authMiddleware = (req, res, next) => { const authorization = req.headers.authorization; if (authorization) { const [bearer, token] = authorization.split(" "); try { jwt.verify(token, secret, (err, result) => { }); } catch (err) { } } next(); }; ```