Solucionado (ver solução)
Solucionado
(ver solução)
23
respostas

Autenticação (JWT)

Boa tarde Flávio

Muito legal a autenticação utilizando o JWT, gostaria apenas de tirar uma dúvida sobre o seguinte cenário:

  • Uma API Rest, onde sua responsabilidade única é gerenciar os usuários da empresa. Onde cada nível de acesso, pertence a um determinado setor, como por exemplo, setor do RH, tem os níveis (Gerente e Colaborador), setor financeiro, segue a mesma linha. Dessa forma eu posso aplicar permissões por setor, assim os funcionários daquele setor, vai herdar as permissões ou restrições. Como a que fizemos no curso, mas sem a parte de fotos, apenas controlar os usuários, e os pacotes de cada usuário faz parte.

    • É possivel no momento que realizar o login, de forma dinâmica, exibir ou esconder, menus e opções de acordo com cada nível de acesso que o setor tenha. Em um template estilo Dashboard Admin?
23 respostas
solução!

Olá André,

Quando você for gerar o JWT, você pode adicionar qualquer informação como payload, por exemplo, um JSON com as permissões do usuário, por exemplo. Daí, toda vez que o usuário for acessar um recurso, a API vai descriptografar o TOKEN e verificar lá no payload se ele possui as credenciais para acessar determinado serviço. É bem flexível o negócio.

Sobre esconder ou exibir partes da UI de acordo com as credenciais do usuário fique atento que o JWT do cliente é criptografado, sendo assim, você precisaria realizar uma requisição para uma API que retorne no formato JSON as credenciais do usuário com base no token enviado. Você pode guardar essa info no localtorage, assim como você guarda o token e utilizá-la para exibir ou não determinada parte da ui.

Belezinha?

Valeu Flávio, vou tentar dessa maneira que disse. Muito Obrigado

Pessoal, estou tentando fazer algo bem similar, porém estava armazenando o nome do usuário em um token e o angular consultava e verificava se ele tinha acesso ou não, porém o usuário poderia muito bem alterar o nome no token e acessar conteúdos restritos.

Flavio, eu já procurei em vários lugares e essa solução é bem interessante, porém ainda sou um pouco leigo no assunto. Aonde tem um exemplo deste método que você falou?

No curso de Mean do Alura!

Flavio, eu estou refazendo este módulo para refrescar a mente sobre os detalhes da aplicação do jwt. Durante a revisão consegui resolver parte do problema:

Consigo colocar um valor no objeto que está sendo assinado no token; no caso inclui no próprio exemplo do curso o seguinte valor:

 var token = jwt.sign( {login: usuario.login, root : usuario.root}, app.get('secret'), {
                     expiresIn: 86400 

                 });

porém para acessar esse valor pelo root em somente uma rota, eu criei uma nova rota no back-end :

 app.use('/users', api.checkRoot);

só que quando eu tento acessar o token do mesmo modo que o .verificaToken porém verificando o token nesta rota ele me retorna um valor undefined. A dúvida é a seguinte: Eu terei que verificar isto dentro da função .verificaToken? Terei que criar um controller no angular para validar conforme o token-interceptor.js? É esse meio que o caminho ou estou fazendo da forma errada?

Não sei o que é. Se vc está reenviando SEMPRE o token e está descriptografando no backend o valor tem que estar lá.

O usuário não pode alterar o token porque ele é criptografado.

É.. vou dar uma olhada no que pode estar acontecendo.... Mas obrigado!

Cole seu código completo. Da api que você está acessando. Talvez eu consiga enxergar algo.

Essa é a sequência que está na rota.

module.exports = function(app){
    var api = app.controllers.auth;
    app.post('/autenticar',api.autentica);
    app.use('/*',api.verificaToken);
    app.use('/users', api.checkRoot);
};

A api para checkar se o usuario é admin: Eu usei com base na api do curso verificaToken

api.checkRoot = function(req, res, next) {
         var token = req.headers['x-access-token']; 
         if (token) {
             jwt.verify(token, app.get('secret'), function(err, decoded) {
                 isRoot = decoded.root;
                 if (isRoot == false) {
                     console.log('Sem acesso para a rota');
                     return res.sendStatus(401);
                 } else {
                     console.log('Permissão aceita')
                     req.usuario = decoded;    
                     next();
                  }
            });
        } else {
            console.log('Sem Token para validação');
            return res.sendStatus(401);
          }
    }

Pelo que eu consegui ver gerando uns logs no console, quando eu tento usar a rota /user ele não mostra o header do token.

O log de uma requisição pra qualquer outra rota :

{ host: 'localhost',
  connection: 'keep-alive',
  accept: 'application/json, text/plain, */*',
  'x-access-token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6InRlc3RlIiwiaWF0IjoxNDY5NzUxNjY0LCJleHAiOjE0Njk4MzgwNjR9.e_yjC4YIWWkOf9PRELCJTo7dRtVceDMhY2DNFiVIrgA',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
  referer: 'http://localhost',
  'accept-encoding': 'gzip, deflate, sdch',
  'accept-language': 'pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4',
  'if-none-match': 'W/"17f-PmV6RRvVRwtjpzWXRjM9bg"' }

mas quando é para a rota /users o header fica assim :

{ host: 'localhost',
  connection: 'keep-alive',
  'upgrade-insecure-requests': '1',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
  'accept-encoding': 'gzip, deflate, sdch',
  'accept-language': 'pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4' }

Depois de fazer mais uns testes eu vi que ele verifica o token normal depois de usar a api.checkRoot.

Tem alguma forma de eu colocar a rota para realizar a api.verificaToken e depois usar a api.checkRoot?

O token precisa ser reenviado a cada requisição depois de você ter obtido no seu cliente. Por isso o uso de interceptors do Angular. Em algum momento você não está reenviando.

Estou fazendo como vc disse Flávio, usando o payload p/ carregar algumas informações do usuário, também estou lendo novamente seu livro de MEAN, p/ ver se tem algo la que possa ajudar, apesar que la usamos o serviço do Github.

A parte de gerenciar a aplicação toda que esta um pouco complicado, pois é assim:

São vários web services rest: - 1 Administração - API Rest com Spring (Spring Security - Basic Auth); - 1 RH - API Rest com Spring (Spring Security - Basic Auth); - 1 Suporte - API Rest com Spring (Spring Security - Basic Auth); - 1 Vendas - API Rest com Spring (Spring Security - Basic Auth); - 1 Controle de Usuário - É o que eu estou desenvolvendo no momento utilizando MEAN.

O front em Angular, vai reunir todas as API Rest.

Mas vou continuar pesquisando mais, ate conseguir.

Mas vc está reenviando o token a cada requisição para o Server? Isso tem que ser feito sempre.

Pelo que eu consegui ver ele está tentando verificar antes de reenviar o token. Se por um acaso eu coloco um next() após o else do checkRoot de sem token, ai ele envia.

pode ser algo relacionado à sequência das rotas?

Consegui resolver parte do problema! Agora só estou procurando um jeito de tratar caso o usuario tenha o acesso como false ele responder com o status 403, porém estou usando como base o verificaToken mas não está funcionando.

André, se quiser eu te mando o código da minha caso seja útil para o seu caso.

Opa Tadeu agradeço Esta no seu git o código??

André.. está sim.

https://github.com/cotts/ticketapp.git

Os arquivos que eu estou tratando estao nos controllers do node em app/controllers/auth.js e tem um controller q recebe o valor em no angular em /public/js/controllers/AdminController.js.

Se tiver alguma dúvida pode me chamar no skype cotts@outlook.com que a gente troca uma ideia.

Muito Obrigado Thadeu

André... atualizei os arquivos com uma configuração que ele valida o payload em uma rota no NOdejs e pelo angular valida e que se ele não tem acesso, redireciona pra pagina principal. Removi uns comentários... o código ainda tá meio desorganizado.. mas esta lá.. qualquer coisa chama...

Eu dei fork no projeto. Eu uso bem pouco o skype, mas esse é meu email pessoal ( andcrow25@gmail.com ).

Muito obrigado mesmo Thadeu, vai ajudar bastante Grande abraço

Show... precisando é só chamar... depois me manda um git do teu projeto...

meu e-mail é thadeu.cotts@gmail.com

Esse projeto é uma ferramenta de gerenciamento de chamados.