7
respostas

Token de autenticação não é aceito pela aplicação

Olá pessoal!

Realizei o curso e estou tendo alguns problemas com a parte de auth. Segui os passos explicados no curso mas quando subo a aplicação, ela está tendo alguns comportamentos estranhos.

Se acesso o localhost:3000 ele não está me redirecionando para a página de login, mesmo eu tendo incluído a rota no main do angular para isso e também ter colocado o o path para /login quando receber uma rejection ou status 401.

Outro comportamento que identifiquei, é que ao acessar um link da aplicação ele me redireciona para a página de login. Até aí tudo bem, é um comportamento já esperado. Porém, quando coloco login o angular recebe o token pelo interceptor.response, no interceptor.request eu tmbm recebo o header com o token, porém continuo recebendo em seguida o status 401.

Já em meu backend eu consigo receber resposta da function de altenticação, porém na function de verificação eu percebi que não estou conseguindo receber o header da requisição:

var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');

module.exports = function(app) {

    var api = {};
    var model = mongoose.model('User');

    api.auth = function(req,res){
        model.findOne({
            username : req.body.username, 
            password : req.body.password
        })
        .then(function(user){
            if(!user){
                console.log('Usuário/Senha inválidos!');
                res.sendStatus(401);
            } else {    
                var token = jwt.sign({username : user.username}, app.get('secret'), {
                    expiresIn: 84600
                });

                console.log('Autenticado: token adicionado na resposta');
                res.end();
            }
        });
    };

api.tokenVerify = function(req, res, next) {

        var token = req.headers['X-NW-Token']; //aqui ele está vindo undefined :(
        if(token) {
            console.log('Verificando Token...');
            jwt.verify(token, app.get('secret'), function(error, decoded) {
                if(error){
                    console.log('Token Rejeitado!');
                    return res.sendStatus(401);
                } else {
                    console.log('Token Aceito!');
                    req.user = decoded;
                    next();
                }
            });
        } else {
            console.log('Token não foi enviado');
            return res.sendStatus(401);
        }
    };

    return api;
};

Segue os codes da parte do angular:

token-interceptor.js

angular.module('biwebapp')
    .factory('tokenInterceptor', function($q, $window, $location) {

        var interceptor = {};

        interceptor.response = function (response) {
            var token = response.headers('X-NW-Token');
            if (token) {
                $window.sessionStorage.token = token;
                console.log('Token armazenado no navegador: ', token);
            } 
            return response;
        };

        interceptor.request = function(config) {
            config.headers = config.headers || {};
            if($window.sessionStorage.token) {
                config.headers['X-NW-Token'] = $window.sessionStorage.token;
                console.log('Adicionando token no header da requisicao para ser enviado ao servidor');
            }
            return config;
        };

        interceptor.responseError = function(rejection) {
            if(rejection != null && rejection.status == 401) {
                delete $window.sessionStorage.token;
                $location.path('/login');
            }

            return $q.reject(rejection);
        };

    return interceptor;

    });

login-controler.js

angular.module('biwebapp')
    .controller('LoginController',function($scope, $http, $location) {

        $scope.user = {};
        $scope.mensagem = '';

        $scope.authenticate = function(){

            var user = $scope.user;

            $http.post('/authenticate', {username : user.username, password : user.password})
                .then(function() {
                    $location.path('/');
                }, function(error){ 
                    $scope.usuario = {};
                    $scope.mensagem = 'Usuário ou Senha inválidos!';
                });
        };
    });

main.js

angular.module('biwebapp', ['myDirectives', 'ngRoute', 'ngResource', 'services'])
    .config(function($routeProvider, $locationProvider, $httpProvider) {

        $locationProvider.html5Mode(true);

        $httpProvider.interceptors.push('tokenInterceptor');

        $routeProvider.when('/', {
            templateUrl: 'partials/index.html',
            controller: 'IndexController'
        });

        $routeProvider.when('/user', {
            templateUrl: 'partials/user.html',
        });

        $routeProvider.when('/clients', {
            templateUrl: 'partials/clientList.html',
            controller: 'ClientsController'
        });

        $routeProvider.when('/clients/update/:bi_id_client', {
            templateUrl: 'partials/updateClient.html',
            controller: 'UpdateClientController'
        });

        $routeProvider.when('/clients/create', {
            templateUrl: 'partials/createClient.html',
            controller: 'CreateClientController'
        });

        $routeProvider.when('/login', {
            templateUrl: 'partials/login.html',
            controller: 'LoginController'
        });

        $routeProvider.otherwise({redirectTo: '/'});

});

Desde já agradeço a atenção de todos!

7 respostas

Sua App e sua API estão em domínios diferentes?

Bom dia Professor Flavio. A API e APP estão no mesmo domínio. Inclusive elas fazem parte de um único projeto.

Você esta usando HTMLMode. Não vai funcionar com o JWT. Por isso que no curso de MEAN eu o desativei. Gmail e outras aplicações usam o hash até hoje sem problema algum.

Veja um exemplo:

https://mail.google.com/mail/u/0/#inbox

Boa noite Professor. Eu desativei o HTMLMode e mesmo assim não funcionou.

Eu percebi que em tokenVerify a var token retorna undefined

var mongoose = require('mongoose');
var jwt = require('jsonwebtoken');

module.exports = function(app) {

    var api = {};
    var model = mongoose.model('User');

    api.auth = function(req,res){
        model.findOne({
            username : req.body.username, 
            password : req.body.password
        })
        .then(function(user){
            if(!user){
                console.log('Usuário/Senha inválidos!');
                res.sendStatus(401);
            } else {    
                var token = jwt.sign({username : user.username}, app.get('secret'), {
                    expiresIn: 84600
                });

                console.log('Autenticado: token adicionado na resposta');
                res.set('X-NW-Token',token);
                res.end();
            }
        });
    };

api.tokenVerify = function(req, res, next) {

        var token = req.headers['X-NW-Token']; 
        console.log(token); //aqui ele está vindo undefined :(
        if(token) {
            console.log('Verificando Token...');
            jwt.verify(token, app.get('secret'), function(error, decoded) {
                if(error){
                    console.log('Token Rejeitado!');
                    return res.sendStatus(401);
                } else {
                    console.log('Token Aceito!');
                    req.user = decoded;
                    next();
                }
            });
        } else {
            console.log('Token não foi enviado');
            return res.sendStatus(401);
        }
    };

    return api;
};

Por isso que ele acaba sempre emitindo status 401. O problema é que não entendi o por que de ele não conseguir pegar o header da requisição.

Bom, vi que você mudou nome de variáveis e de métodos. Então, precisa manter uma paridade com o seu código escrito em Angular.

Se você me dá a certeza que sua app Angular e sua API estão no mesmo domínio (porque se não estivesse, daria problema), você precisa realizar algumas testes no seu interceptar e saber se ele esta sendo chamado lá no lado do Angular. Tipo, colocar um console log e coisa parecida.

Agora, se você estiver acessando via Angular algum recurso que não é protegido, sua autenticação não funcionará. Você só será redirecionado para login se você estiver acessando um recurso protegido.

Por fim, você ganha o token no momento em que se autentica e sua APP Angular deve guardar e reenviar o token toda vez que requisições forem feitas. Se o token esta vazia, presumo que após a autenticação você não esta guardando o token ou não esta o reenviando. São esses pontos a analisar.

Então professor. Eu percebi, olhando no console do chrome, que um GET para uma url que não está sendo autorizada pela validação do token.

Analisando melhor, percebi que este GET vem de um controller que tem como finalidade exibir alguns botões personalizados (com imagens, urls, títulos, classe bootstrap e descrições diferentes um do outro). Eu segui o conceito da sua aula de Angular, onde foram exibidas as fotos no alurapic

Eu vou colar aqui o controller para ilustrar melhor o que foi feito:

angular.module('biwebapp').controller('IndexController', function($scope) {

    $scope.idxs = [
    {
        url : './#/user',
        titulo : 'Cadastro de Usuários',
        descricao : 'Crie usuários para acesso e administração do sistema',
        urlImg : './img/man.png',
        class : 'thumbnail box'
    },
    {
        url : './#/clients',
        titulo : 'Cadastro de Clientes',
        descricao : 'Cadastre clientes para consumo das aplicações de BI',
        urlImg : './img/businessman.png',
        class : 'thumbnail box'
    },
    {
        url : './#/dataBases',
        titulo : 'Cardápio de Bases',
        descricao : 'Confira as bases disponíveis em nosso Storage de Dados',
        urlImg : './img/cloud.png',
        class : 'thumbnail box'
    },
    {
        url : './#/analysis',
        titulo : 'Analises',
        descricao : 'Confira as analises disponíveis em nossas aplicações',
        urlImg : './img/analysis.png',
        class : 'thumbnail box'
    }
    ];

});

Depois, utilizo o ng-repeat para exibir as fotos de $scope.idxs

<div class="row fadein" ng-controller="IndexController">

    <div class="col-sm-4 col-md-3" ng-repeat="idx in idxs">
        <a href="{{idx.url}}" class="{{idx.class}}">
            <img src="{{idx.urlImg}}" class="img-responsive">
            <div class="caption">
                <h3 class="text-center">{{idx.titulo}}</h3>
                <p class="text-center">{{idx.descricao}}</p>
            </div>
        </a>
    </div>

</div>

Eu não entendo o por que de estar aparecendo um GET em meu console (Chrome) para a url http://localhost:3000/%7B%7Bidx.urlImg%7D%7D se não tem nada em $scope.idxs além das imagens e demais parâmetros que utilizo na página. Teria alguma forma de este famigerado GET não aparecer na minha aplicação?

Ex do que aparece no console Chrome:


GET http://localhost:3000/%7B%7Bidx.urlImg%7D%7D 401 (Unauthorized)          %7B%7Bidx.urlImg%7D%7D:1

Mais uma vez agradeço a sua atenção!!!

Então, você precisa verificar a precedência da ativação da rota que verifica a autenticação. Você deve estar tentando acessar algo que era para ser publico e que esta privado (requer autenticação) sem se autenticar antes.

Você não pode ativar os middewares de rotas em qualquer ordem, inclusive eu falo isso no vídeo. Talvez seja um caminho checar no local onde você ativa os middewares de rotas, inclusive aquele que bloquei o acesso à sua aplicação.

Pela a informação que você colocou, sua pasta de assets publicas esta sendo bloqueada pelo midleware de autenticação, o que não deveria acontecer.