Exemplo de Autenticação em Node.JS - Setup inicial
Autor: Giovane Boaviagem | Publicado: 2015-01-21T10:54:00-08:00

Demais posts desta série:


Passport e Autenticação Local
Autenticação via Twitter e unindo contas
Autenticação via Google
Autenticação via Facebook



Olá a todos,

Estava brincando um pouco com node.js e percebi que muitos tutoriais em português sobre autenticação não cobrem todos os passos para fazer um site minimamente estruturado que permita uma escalabilidade interessante. Sendo assim, vou tentar cobrir esta lacuna fazendo um exemplo de um site em node.js com autenticação por usuário/senha,&nbsp; Facebook, Google, e Twitter. Porém, o principal foco deste exemplo estará na estruturação da aplicação, para que ela seja amplamente escalável e aplicável na maioria dos casos de websites envolvendo CRUDs, e autenticação.

Este tutorial é aplicado a qualquer um que deseja aprender mais sobre programação web. É desejável que se tenha algum conhecimento em programação, principalmente na linguagem JavaScript.

Lembrando que o projeto completo está disponível aqui, e este tutorial foi baseado neste &nbsp;excelente&nbsp;link.

As ferramentas necessárias para começarmos são:

Node.js, disponível aqui
Um bom editor de texto. Qualquer um que não seja o bloco de notas tá valendo.

Caso você use Windows, acho interessante você possuir ainda estas ferramentas:

Visual Studio C++ Express;
ConEmu, um prompt de comando MUITO melhor do que o padrão.

Feito isso, com o ConEmu, vamos agora instalar o express-generator, que é um gerador de infra-estrutura mínima para qualquer aplicação em node.js, utilizando o Express:

npm install -g express-generator


Após a instalação (no qual usamos a flag -g, que indica que o pacote será instalado globalmente), criamos o nosso projeto:

express --hbs node-auth-example


Ao final desta etapa, alguns diretórios e arquivos foram criados automaticamente. Porém, ainda precisamos fazer alguns ajustes. O primeiro deles é instalar as dependências que faltam no projeto. Isso porque o express-generator criou os arquivos básicos (incluindo o package.json com as dependências), mas não os instalou. Por isso, devemos instalar as dependências, acessando a pasta do projeto e digitando:

npm install


Agora, nós podemos testar a nossa aplicação. Digite npm start e acesse http://localhost:3000 no seu navegador para ver a página da aplicação. 

Legal, né? Não muito? Concordo. Nossa aplicação não está muito emocionante. Mas calma, que estamos só começando.

Banco de Dados

Um dos elementos essenciais para nossa aplicação é o banco de dados onde armazenaremos as informações dos usuários. Utilizaremos aqui o MongoDB, porém não precisaremos instalar localmente. Usaremos o MongoLab, que é um serviço de hospedagem de bases em MongoDB (calma que tem plano free :D). Depois de fazer seu cadastro e logar no sistema, Clique em um botão chamado New, no canto superior direito. Após o clique, aparecerá a seguinte tela:



Clique na imagem para ampliar

Mais para baixo, vemos uma aba chamada Single Node (Dentro da seção Plan) e nela, uma opção chamada Sandbox. Clique nesta opção, digite um nome para o banco e clique no botão Create new MongoDB Deployment. No meu caso, ficou assim:




Depois, voltamos para o dashboard e clicamos no banco que acabamos de criar. A seguinte tela vai aparecer:





Na aba Users, crie um usuário para acessar o banco. E não se esqueça de copiar a URI.

De volta à nossa aplicação, vamos agora instalar o drive de acesso ao banco, o mongoose:

npm install --save mongoose


Caso você esteja usando o Windows e algum erro ocorreu durante a instalação, você precisa especificar a versão do visual studio através da flag --msvs_version. No meu caso, ficou assim:

npm install mongoose --save --msvs_version=2013


Em seguida, criamos uma pasta chamada config e dentro dela um arquivo chamado config.js com o seguinte formato:

module.exports={                             
        db:{                                 
                sgbd:'mongo',            
                username:'seu_usuario',             
                password:'sua_senha',            
                host:'ds031741.mongolab.com',
                port:31741,                  
                database:'node-auth-example',
        }                                    
};                                           


Para finalizar esta etapa, vamos adicionar algumas linhas ao arquivo app.js, localizado na raiz do projeto. As primeiras linhas do arquivo são assim:

var express = require('express');            
var path = require('path');                  
var favicon = require('serve-favicon');      
var logger = require('morgan');              
var cookieParser = require('cookie-parser'); 
var bodyParser = require('body-parser');     
                                             
var routes = require('./routes/index');      
var users = require('./routes/users');       
                                             
var app = express();                         
                                                                         


Após a criação da variável app, adicionaremos o seguinte código:

var config=require('./config/config.js');

/**********************
 *** BANCO DE DADOS ***
 **********************/
var dbname=config.db.sgbd;
var username='';
var password='';
var dbPort='';
var host='';
var database='';
var url='';
switch(dbname){
    case 'mongo':
        var opts={
            server:{
                socketOptions:{keepAlive:1}
            }
        };
        username=config.db.username;
        password=config.db.password;
        dbPort=config.db.port;
        host=config.db.host;
        database=config.db.database;
        url='mongodb://'+username+":"+password+"@"+host+":"+dbPort+"/"+database;
        
        var mongoose=require('mongoose');
        mongoose.connect(url, opts);
        break;
    default:
        throw new Error("Banco de dados desconhecido: "+dbname);
        break;
}



Rotas

Agora, vamos tratar das rotas da nossa aplicação. Isso significa que vamos dizer para onde vai cada uma das URLs acessadas pelo usuário. Portanto, precisamos algo que nos permita criar as rotas de forma simples. O modo padrão do express (utilizando o objeto Router) é bom, mas existe uma junção muito grande da rota e da função que a gerencia. Para manutenções futuras isso pode ser um problema. O ideal é que a rota seja o mais separado possível do controller e é isso que vamos fazer agora. Para implementar, vamos adaptar as rotas que o express já disponibiliza por padrão para esta nova realidade. Com isso implementado, as rotas estarão bem mais organizadas.

Crie um arquivo chamado routes.js, na pasta config, com o seguinte conteúdo:

module.exports={                                                                                          // Caso o método da rota seja diferente de GET, utilizar o nome do método antes da rota (Ex: 'POST /nome/nome2')
        '/':{
                controller:'IndexController',
                action:'index',
        },                                                                                               
        '/users':{ 
                controller:'UsersController',       
                action:'index',   
        },
};                                                                                                        


Feito isso, vamos criar os controllers da nossa aplicação. Renomeie a pasta routes para controllers e dentro dela, renomeamos o arquivo index.js para IndexController.js e users.js para UsersController.js. Depois, O primeiro, ficará assim:

var IndexController={                                   
        index:function(req,res){                        
                res.render('index',{title: 'Express'}); 
        }                                               
};                                                      
                                                        
module.exports=IndexController;                         


E o segundo:

var UsersController={                                                  
        index:function(req,res){                                       
                res.send('users controller: respond with a resource'); 
        }                                                              
};                                                                     
                                                                       
module.exports = UsersController;                                                           


Agora vamos juntar tudo. Criaremos um arquivo que vai carregar as rotas de acordo com as descrições no arquivo config/routes.js. Criaremos um arquivo chamado route_loader.js na pasta lib com o seguinte conteúdo:

module.exports=function(app){                                                              
        var routes=require('../config/routes');                                            
        var fs=require('fs');                                                              
                                                                                           
        var controllers_folder=__dirname+'/../controllers';                                
                                                                                           
        for(var k in routes){                                                              
                var route=routes[k];                                                       
                                                                                           
                var url=k;                                                                 
                var controller_filename=route.controller;                                  
                var action_name=route.action;                                              
                var method=(route.method)? route.method.toLowerCase() : 'get';             
                                                                                           
                // carregando a rota                                                       
                var controller=require(controllers_folder+"/"+controller_filename+".js");  
                app[method](url, controller[action_name]);                                 
        }                                                                                  
};                                                                                         



Agora, é só chamar a função no arquivo app.js. Primeiro, eliminamos as seguintes linhas do arquivo:

var routes = require('./routes/index'); 
var users = require('./routes/users');

// E

app.use('/', routes);     
app.use('/users', users);   


Depois, adicionamos as seguintes linhas:

/*************                      
 *** ROTAS ***                      
 *************/                     
require('./lib/route_loader')(app); 


Agora, execute a aplicação e perceba que nada mudou (pelo menos externamente). Agora, nossas rotas estão bem mais organizadas. Pode-se ainda, colocar as rotas para página não encontrada e erro interno de servidor dentro do arquivo lib/route_loader.js. Mas isso é opcional. Remova também o UserController.js e suas referências. Não precisaremos mais dele.

No próximo post, continuaremos nossa jornada pela autenticação com Node.JS, express e passport.

Inté.

Demais posts desta série:

Passport e Autenticação Local
Autenticação via Twitter e unindo contas
Autenticação via Google
Autenticação via Facebook