4.3.1 Arquitetura MVC
Oback end do trabalho é a API. Para estabeler uma estrutura de projeto de API REST sólida e escalável, utilizamos do paradigma MVC definido na seção 2.5. Por se tratar de uma API, a camada de view do MVC fica subentendida como sendo o front end da aplicação. No projeto desenvolvido em NodeJS, a camada de controller foi agrupada em routes e controllers.
Capítulo 4. O jogo Decifre 45
4.3.1.1 Controllers
Dentro da nossa camada de controladores existem duas divisões: Rotas e Con-troladores. Como já expliado anteriormente, as rotas são as responsáveis por receber a requisição do cliente e a redirecionar para um controlador específico. O exemplo do arquivo de rotas para o contexto de rodadas pode ser visto emhttps://github.com/Rodrigoaz7/
descifre-back-end/blob/master/src/routes/rodada.js.
Inicialmente são feitas as importações de objetos e métodos que iremos utilizar na rota. O objetopermissao possui um conjunto de funções relacionadas as permissões de usuários no sistema, cujo será abordado na próxima subseção. O objeto variaveis possui dados globais de toda a aplicação, como por exemplo, a url base da aplicação. Os outros objetos importados são referentes aos controladores que serão chamados a cada URL e a cada método HTTP capturado pelas rotas.
Logo após as importações temos as definições das nossas rotas, definidas cla-ramente em rotas para administradores e rotas para usuários do sistema. Pegando o exemplo da primeira rota definida, vemos que a rota (definida como método da bibli-oteca Express definida na subseção 2.9.1) é responsável por interceptar requisições na URL "/administrador/rodadas"para métodos POST. O segundo parâmetro do método é um parâmetro de autenticação e permissão, definido na próxima subseção. Já o ter-ceiro e último parâmetro, é o controlador que chamamos para processar a requisição e retornar uma resposta. O controlador responsável por atender a rota dada como exem-plo pode ser vista em https://github.com/Rodrigoaz7/descifre-back-end/blob/
master/src/controllers/administrador/rodadas/criarRodada.js.
A função cadastrarRodada pode ser vista como a função que é chamada pela rota para criar uma nova rodada. Inicialmente há uma validação dos dados de entrada enviados pelo cliente, e depois criado a instância do objeto Rodada (objeto da ODM Mongoose, definido na subseção 2.9.3.1). Por fim, é chamado um método genérico para salvar registros utilizando do objeto mongoose.
Com a rodada criada sem erros, o código gera ojobde finalização da rodada definido na subseção 4.1.3.1 e retorna o json de resposta para o cliente obtendo a mensagem e o status HTTP a partir de Enums declarados dentro do projeto.
4.3.1.2 Models
Na seção anterior vemos a importação de um objeto chamado Rodada no arquivo de controlador de rodadas. Este objeto é utilizado pela nossa ODM, o mongoose, para fazer o mapeamento da coleção Rodada do nosso banco de dados para um objeto no nosso código. O mapeamento pode ser visto emhttps://github.com/Rodrigoaz7/descifre-back-end/
blob/master/src/models/Rodada.js.
Capítulo 4. O jogo Decifre 46
O conceito dos campos da rodada podem ser revistos na seção 4.2. Aqui declaramos o objeto Rodada adotando os tipos explicitamente para cada campo da nossa coleção. Por exmeplo, o tipoObjetId é um tipo vindo da biblioteca do mongoose para tipar os ids do mongo. Todos os outros tipos são primitivos, como String, Date e Number.
Com as coleções mapeadas pelo mongoose, todas as operações envolvendo banco de dados dentro do sistema são usados por manipulação desses objetos, sem qualquer lógica ou sintaxe própria do mongo.
4.3.2 Autenticação
Um ponto importante a destacar neste projeto é a autenticação e as permissões dos usuários. Toda a modelagem dos usuários a nível de banco de dados, juntamente com suas permissões são definidos na seção 4.2. Nesta subseção a abordagem da autenticação e das permissões serão abordadas a nível de código, obedencendo a arquitetura do modelo MVC.
4.3.2.1 Cadastro de Usuários
O cadastro de novos usuários no sistema segue o mesmo padrão MVC explicado na subseção 4.3.1.1, possuindo uma rota e um controlador. O Código 4.3 mostra a definição da rota para receber requisições POST pela URL "/publico/cadastro".
1 module . exports = ( a p p l i c a t i o n ) => {
2 a p p l i c a t i o n . post ( ‘ ${ v a r i a b l e s . base }/ publico / cadastro ‘ , ( req , r e s ) => { c o n t r o l l e r C a d a s t r o . r e a l i z a r C a d a s t r o ( req , r e s ) }) ; 3 } ;
Código 4.3 – Trecho de Rotas para Cadatro de Novos Usuários
O código completo do controlador chamado pela rota, por sua vez, é definido e dis-ponibilizado em https://github.com/Rodrigoaz7/descifre-back-end/blob/master/
src/controllers/publico/autenticacao/cadastro.js.
Neste controlador podemos notar primeiramente a validação dos dados de entrada do cliente. Caso a primeira validação ocorra com sucesso, podemos prosseguir com a encriptografia da senha utilizando do algoritmo hash definido na seção 2.11. Logo após a senha encriptografada ter sido gerada, criamos o dado da coleção de Pessoa seguido da criação da coleção de Usuário com os dados passados pela requisição. Com todos os passos anteriores completados com sucesso, criamos um token utilizando da biblioteca jsonwebtoken passando os dados do usuário como um objeto json e o tempo de expiração como sendo trezentos e sessenta horas. A geração do token pela biblioteca pode ser vista no Código 4.4.
Capítulo 4. O jogo Decifre 47
1 exports . gerarToken = ( inf ormati ons=true, timeExpiresHours =24) =>
{
2 timeExpiresHours = ‘ ${ timeExpiresHours }h ‘ ;
3 l e t token = jwt . s i g n ( informations , s e c r e t , { e x p i r e s I n : timeExpiresHours }) ;
4 return token ; 5 } ;
Código 4.4 – Geração de Token de Usuário
No código acima, o parâmetroinformationsé o objeto json com os dados do usuário que serão adicionados a formação do token, e o parâmetrotimeExpiresHours é o tempo, em horas, em que o token irá expirar. O campo secret passado no métodosign da biblioteca é a chave secreta utilizada no sistema para encriptografia dos dados.
Com o token criado e salvo na base do usuário, o controlador retorna ao cliente uma mensagem de sucesso de status 200 com o token gerado, sendo o envio deste token necessário e obrigatório em todas as outras rotas internas do sistema. A validação da passagem correta deste token é definido por meio de ummiddleware.
Ologindo usuário segue o mesmo padrão do cadastro, a única diferença significativa, é que neste cenário, o usuário irá enviar apenas à API o email e sua senha. O sistema, por sua vez, irá verificar se existe um usuário com estes dados na base,e caso sim, um novo token atualizado será criado e armazenado para este usuário e enviado de volta ao cliente.
4.3.2.2 Middleware
No subseção 4.3.1.1 existem alguns exemplos de declarações de rotas para o ce-nário de rodadas. Para cada um destas rotas existe um segundo parâmetro passado, sendo "permissao.administrador"ou "permissao.usuario". Estes parâmetros são chamados de middlewares da nossa aplicação. O middleware é o responsável por identificar au-tenticações e permissões do usuário em cada requisição à partir do token enviado. O exemplo da atuação domiddleware para rotas em que apenas usuários administradores têm acesso pode ser visto em https://github.com/Rodrigoaz7/descifre-back-end/
blob/master/src/middlewares/permissoes/index.js.
Primeiramente, o middleware verifica se algum token foi passado na requisição, seja pelo corpo, cabeçalho ou parâmetro na URL. Caso o token for enviado na requisição fazemos a busca dele na nossa base de dados. Se o dado não encontrado, uma mensagem de "token inválido"é retornado ao cliente, já no caso contrário o token é descriptografado pela biblioteca jsonwebtoken. O token descriptografado fornece o objeto json contendo as informações do usuário, permissões e a sua data de expiração. Em um primeiro momento, a data de expiração é testada e, caso vencida, um erro de "Você precisa renovar seu token"é
Capítulo 4. O jogo Decifre 48
retornado ao cliente. No caso do token existir e não estiver com data expirada, percorremos oarray de permissões do usuário para verificar se a permissão de "Administrador"consta para ele. No caso do usuário conter a permissão em questão, o middleware informa à rota para continuar prosseguindo a chamada ao controlador normalmente, mas caso contrário, um erro de "Usuário não autorizado"é disparado ao cliente.