Parte 2 NodeWallet - Configurando as models iniciais e criando uma Autenticação com JWT
Published: 2023-10-11 11:21:17

Após a criação do projeto e as configurações inicias vamos, finalmente, partir para o desenvolvimento das funcionalidades. Como primeira funcionalidade, pensei na implementação do login (registro e autenticação) com JWT (Json Web Token) para uma maior segurança do projeto.

Primeiro de tudo vamos configurar a migration Usuário, onde vão ser definidos os campos que vão ser criados na tabela.

```
'use strict';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up (queryInterface, Sequelize) {
    await queryInterface.createTable('Users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
      },
      username: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      email: {
        type: Sequelize.STRING,
        allowNull: false,
        unique: true
      },
      password: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      }
    })
  },

  async down (queryInterface, Sequelize) {
    await queryInterface.dropTable('users');
  }
};

```
Aqui é onde os campos da entidade são criados dentro do banco, sendo necessário informar o tipo do campo, se ele pode ser nulo, se ele vai se autocompletar, se é um campo único e tambem se ele é uma chave primária (usada para se relacionar com outras tabelas).


Com a migration criada, vamos partir para a criação da Model, onde vão ser definidos os tipos dos dados e também métodos para a alteração desses mesmos dados


```
const { Model } = require('sequelize');
const bcrypt = require('bcrypt');

module.exports = (sequelize, DataTypes) => {
    class User extends Model {
        static associate(models) {

        }
    }

    User.init(
        {
            username: DataTypes.STRING,
            email: DataTypes.STRING,
            password: DataTypes.STRING,
        },
        {
            sequelize,
            modelName: 'User',
            hooks: {
                beforeCreate: async(user) => {
                    if(user.password) {
                        const salt = await bcrypt.genSalt(10);
                        user.password = await bcrypt.hash(user.password, salt);
                    }
                },
            },
        }
    );
    
    return User;
}
```
Essa é uma estrutura básica de uma Model, onde eu defino os tipos de dados que cada campo pode aceitar e tambem crio uma função que encripta a senha antes de criar o usuário.

Logo depois da model, partimos para a criação do controller, parte que é responsável por receber e processar as requisições feitas através das rotas

```
const { User } = require('../models');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

module.exports = {
    async register(req, res) {
        try {
            const { username, email, password } = req.body;
            const user = await User.create({username, email, password});
            res.status(201).json({user}); 
        } catch (error) {
            console.error(error);
            req.status(500).json({ error: `Internal Server Error` });
        }
    },

    async login(req, res) {
        try {

            const { email, password } = req.body;
            const user = await User.findOne({ where: {email} });
            
            if(!user) {
                return res.status(404).json({ error: `Invalid email or password` });
            }

            const isPasswordValid = await bcrypt.compare(password, user.password);

            if(!isPasswordValid) {
                return res.status(404).json({ error: `Invalid email or password` });
            }

            const payload = {
                user
            };

            const secretKey = 'yourSecretKey';

            const options = {
                expiresIn: '12h'
            };

            token = jwt.sign(payload, secretKey, options);

            res.status(200).json({ success: `Successful Login`, user: user, token: token });

        } catch (error) {

            console.error(error);
            res.status(500).json({ error: `Internal server error` });

        }
    },
}
``` 

E antes de finalizar vamos a criação do arquivo de rotas, nesse projeto eu optei por separar as rotas em diferentes arquivos, como ainda estamos no começo do projeto por agora teremos apenas o arquivo `authRoutes.js`

```
const express = require('express');
const router = express.Router();

const UserController = require('../controllers/UserController');

router.post('/register', UserController.register);
router.post('/login', UserController.login);

module.exports = router;
```

Agora para finalizar, criamos o arquivo principal do projeto, resolvi chamá-lo de `index.js`.

```
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

app.use('/auth', require('./routes/authRoutes'));

app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
})
```

Assim temos um login completamente funcional, que faz conexão com o banco de dados e tambem faz uso do JWT!

Até a próxima