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

Autenticação por token

Boa noite, estou tentando consumir um Rest, onde no mesmo ha autenticação por Token.

Estou tentando utilizar interceptor para enviar o token, porem o mesmo não chegar no cabeçalho da requisição no servidor.

segue trecho do código: Por enquanto ainda estou enviando no token hard-coded mesmo. Não se assuste é so para testar. rs

Vue.http.interceptors.push(function (request, next) {
    request.headers.set('x-access-token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg');
    next();
});

No server, estou executando um

console.log(req.headers);

E o conteúdo vem assim:

{ host: 'localhost:3000',
  connection: 'keep-alive',
  'access-control-request-method': 'GET',
  origin: 'http://localhost:8080',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  'access-control-request-headers': 'x-access-token',
  accept: '*/*',
  referer: 'http://localhost:8080/cargas',
  'accept-encoding': 'gzip, deflate, sdch, br',
  'accept-language': 'pt-BR,pt;q=0.8' }

Ou seja não vem o x-access-token. O que mais posso fazer?

38 respostas

O Fabricio!

Você consegue verificar se o header é enviado pelo browser, tipo, antes de chegar no seu server?

Quero destacar a hipótese do teu server estar renovendo essa info do header antes dele te passar o request. Isso porque não conheço seu back.

Flavio, acredito que seja algo no client, pois se testo via Postman, funciona, segue abaixo os headers capturados no server quando a requisicao é do cliente e quando é do cliente.

Header Requisicao Via Postman

{ host: 'localhost:3000',
  connection: 'keep-alive',
  'cache-control': 'no-cache',
  'x-access-token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  'postman-token': '29faff39-4cdf-24e6-7aba-9957b7731ab9',
  accept: '*/*',
  'accept-encoding': 'gzip, deflate, sdch, br',
  'accept-language': 'pt-BR,pt;q=0.8' }

Header Requisicao Via Cliente com Vue.js

{ host: 'localhost:3000',
  connection: 'keep-alive',
  'access-control-request-method': 'GET',
  origin: 'http://localhost:8080',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  'access-control-request-headers': 'x-access-token',
  accept: '*/*',
  referer: 'http://localhost:8080/cargas',
  'accept-encoding': 'gzip, deflate, sdch, br',
  'accept-language': 'pt-BR,pt;q=0.8' }

Oi Fabricio, eu vou dar uma analisada. Quando a gente resolver, estou até pensando em colocar em "Dicas e Truques" essa parte de inteceptador.

Assim que eu descobrir eu te pingo aqui.

se você colocar um console.log no interceptador, ele é exibido? O que precisamos saber é se o interceptor é chamado.

Você já tentou através de Vue.http.headers.common?

É chamado sim, foi a primeira coisa que testei

Vue.http.interceptors.push(function (request, next) {
    request.headers.set('X-Access-Token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg');
    console.log('request.headers');
    console.log(request.headers);
    next();
});

Imagem do Chrome mostrando o console http://prntscr.com/el2k9g

Ja havia tentado também



Vue.use(VueResource);
Vue.http.options.root = 'http://localhost:3000';
Vue.http.headers.common['X-Access-Token'] = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg';


Vue.http.interceptors.push(function (request, next) {
    //request.headers.set('X-Access-Token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg');
    console.log('request.headers');
    console.log(request.headers);
    next();
});

Epa, espera um pouco! Já olhou no console do Chrome? Se tem alguma mensagem de erro dizendo que não pode usar o header?

Rapaz, esta funcionando perfeito aqui. O problema deve estar no seu server.

Eu fiz assim no Vue:

Vue.http.interceptors.push((request, next) => {

    request.headers.set('x-access-token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg');
    console.log('Lidando com o request');

    next(response => console.log('Lidando com a resposta'));

});

Só que no server, ele tem que estar habilitdo para poder lidar com o header x-access-token. Você habilitou?

Se der alguma problema na requisição, aparece um warnning no console do Chrome.

Agora não sei.

Cola ai o código completo do arquivo no qual você declarou o interceptor.

Olhe a resposta do meu server:

API escutando na porta: 3000
{"host":"localhost:3000","connection":"keep-alive","accept":"application/json, text/plain, */*","origin":"http://localhost:8080","x-access-token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36","referer":"http://localhost:8080/","accept-encoding":"gzip, deflate, sdch, br","accept-language":"pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4","if-none-match":"W/\"f08f-ToD+fvMDKJnxGT+30wZ12Q\""}

Você fez o teste do console.log? Para saber se o interceptador esta sendo chamado? Isso é importante, se ele não esta sendo chamado.. ai o problema é outro.

Aliás, mais uma dica. A galera tem gostado mais de usar o Authorization do que o x-access-token. Mas isso não faz diferença para nosso problema.

Aqui funcionou mais uma vez. Cheguei a colocar como uma dica em

https://cursos.alura.com.br/course/vue-parte2/task/25540

Agora, no seu caso, não sei ao certo porque o header não esta sendo enviado. É por isso que preciso saber se pelo menos seu interceptador estar sendo chamado, aquele console.log que pedi para você colocar.

Vi algo estranho pelo server, aparentemente o client faz dois requests. A primeira vai sem o x-access-token no header, porem vai com a chave access-control-request-headers onde o conteúdo da mesma é x-access-token.

Logo em seguida faz outro request onde vai a chave x-access-token no reader com o token.

Veja as duas imagens abaixo, onde trato duas situacoes.

-Situação sem tratar access-control-request-headers http://prntscr.com/el2wx1

-Situação tratando access-control-request-headers http://prntscr.com/el2y3f

Meu main.js onde esta o interceptor

import Vue from 'vue'
import App from './App.vue'

import VueResource from 'vue-resource';
import VueRouter from 'vue-router';
import { routes } from './routes';


import 'bootstrap/dist/css/bootstrap.css';
import 'jquery/dist/jquery.js';
import 'bootstrap/dist/js/bootstrap.js';


Vue.use(VueResource);
Vue.http.options.root = 'http://localhost:3000';
//Vue.http.headers.common['X-Access-Token'] = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg';


Vue.http.interceptors.push(function (request, next) {
    request.headers.set('X-Access-Token', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg');
    next();
});

Vue.use(VueRouter);


const router = new VueRouter({
    routes,
    mode: 'history'
});


new Vue({
    el: '#app',
    router,
    render: h => h(App)
})

meu express.js, onde habilito o X-Access-Token no server

var express = require('express')
    ,app = express()
    ,bodyParser = require('body-parser')
    ,consign = require('consign')
    ,path =  require('path');

app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json({limit: '50mb'}));
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-Access-Token");
    res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
    next();
});

consign({ cwd: 'app'})
    .include('models')
    .then('api')
    .then('routes/auth.js')
    .then('routes')
    .into(app);



module.exports = app;

Bom, como você esta verificando os headers que chegaram ao servidor? Aqui eu estou fazendo

    // console.log(JSON.stringify(req.headers));

Lembre-se que quando você esta fazendo há a preflight request. Será que é isso que esta te confundindo? Não sei.

https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request

Mas o header, consegue acessar no server?

Flavio, da uma olhada ai no meus ultimos posts, mandei duas imagens onde mostro como verifico o header e uma situacao que achei estranha

(eu vi, mas você colocou imagem, complica aqui para mim...é melhor mesmo colar o que é apresentado).

Os dois request devem ser por causa do CORS, o request de preflight que ele verifica se pode colocar a info no header. Esse não vai ter o header mesmo, só depois de autorizado que ele coloca a info no header se não me engano.

Aliás, no meu server aqui que testei fiz isso:

No server que testei eu fiz assim:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  res.header('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS');
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, x-access-token");
  next();
});
solução!

Vamos lá...

Se no meu código do server onde verifico o token Deixo com abaixo, na primeira requisição não vem o token

Código

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

    var token = req.headers['x-access-token'];


    console.log('**************************antes');
    console.log(req.headers);
    //console.log(token);
    console.log('**************************depois');

    if (token) {
        try {
            var decoded = jwt.decode(token, segredo);

            if (decoded.exp <= Date.now()) {
                res.json(400, {error: 'Acesso Expirado, faça login novamente'});
            }

            model.findOne({ _id: decoded.iss }, function(err, user) {
                if(err)
                    res.status(500).json({message: "erro ao procurar usuario do token."})
                req.user = user;
                return next();
            });

        } catch (err) {
            return res.status(401).json({message: 'Erro: Seu token é inválido'});
        }
    } else {
        res.status(401).json({message: 'Token não encontrado ou informado'});
    }
}

Console

**************************antes
{ host: 'localhost:3000',
  connection: 'keep-alive',
  'access-control-request-method': 'GET',
  origin: 'http://localhost:8080',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  'access-control-request-headers': 'x-access-token',
  accept: '*/*',
  referer: 'http://localhost:8080/cargas',
  'accept-encoding': 'gzip, deflate, sdch, br',
  'accept-language': 'pt-BR,pt;q=0.8' }
**************************depois

Caso eu adicione no início o if

 if(req.headers['access-control-request-headers'])
 return next();

Deixando o código assim:

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

    var token = req.headers['x-access-token'];


    console.log('**************************antes');
    console.log(req.headers);
    //console.log(token);
    console.log('**************************depois');

    if(req.headers['access-control-request-headers'])
        return next();

    if (token) {
        try {
            var decoded = jwt.decode(token, segredo);

            if (decoded.exp <= Date.now()) {
                res.json(400, {error: 'Acesso Expirado, faça login novamente'});
            }

            model.findOne({ _id: decoded.iss }, function(err, user) {
                if(err)
                    res.status(500).json({message: "erro ao procurar usuario do token."})
                req.user = user;
                return next();
            });

        } catch (err) {
            return res.status(401).json({message: 'Erro: Seu token é inválido'});
        }
    } else {
        res.status(401).json({message: 'Token não encontrado ou informado'});
    }
}

O console fica assim:

**************************antes
{ host: 'localhost:3000',
  connection: 'keep-alive',
  'access-control-request-method': 'GET',
  origin: 'http://localhost:8080',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  'access-control-request-headers': 'x-access-token',
  accept: '*/*',
  referer: 'http://localhost:8080/cargas',
  'accept-encoding': 'gzip, deflate, sdch, br',
  'accept-language': 'pt-BR,pt;q=0.8' }
**************************depois
**************************antes
{ host: 'localhost:3000',
  connection: 'keep-alive',
  accept: 'application/json, text/plain, */*',
  origin: 'http://localhost:8080',
  'x-access-token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1OGM5MzRmOTM4OWVkODhjMmRlY2NiYmYiLCJleHAiOjE0OTAxODY0Mjg5ODl9.dG_jHBGNQZtNNECqkM2zNR8LPBu1gG86dF0CIJaH0eg',
  'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
  referer: 'http://localhost:8080/cargas',
  'accept-encoding': 'gzip, deflate, sdch, br',
  'accept-language': 'pt-BR,pt;q=0.8',
  'if-none-match': 'W/"58ff3-cvFBChi9XY9SbP6cZoOVCw"' }
**************************depois

Ai funciona.. Não estou sabendo se a maneira de tratar esta primeira requisição é assim mesmo.

Boa!

É exatamente isso que esta acontecendo,

Como você escreveu "Os dois request devem ser por causa do CORS, o request de preflight que ele verifica se pode colocar a info no header. Esse não vai ter o header mesmo, só depois de autorizado que ele coloca a info no header se não me engano."

Os dois requestes estão caindo onde verifico o token, como o primeiro não vem com o token e eu retorno sem autorização, ele nem faz o segundo.

Ai coloquei o if para tratar isso. So que achei muito estranho ter que fazer isso.

Você esta usando autenticação.. isso me passou desapercebido...

No curso de MEAN (você fez) não há preflight porque a API é no mesmo host do server. Por isso lá não tivemos que dar um tratamento especial.

Então, até "segunda ordem", sua solução esta OK, porque precisa lidar com o preflight. No caso do teste que fiz, meu servidor não estava protegido, não havia proteção na API.

Dá uma olhada aqui. Veja se ajuda.

(vou demorar a responder agora.. comecei uma tarefa aqui)...

https://cursos.alura.com.br/forum/topico-angular-nao-acessa-token-enviado-por-nodejs-30544

Bom, a sua solução faz sentido para mim.

Então ... fechou....

Vou te passar um módulo que habilita CORS para você testar. Ele fará por debaixo dos panos esse return do seu código.

Vou testar

Use esse módulo para habilitar CORS.

npm install cors --save

Depois vai lá, faz o require:

var cors = require('cors')
// bla bla bla 
app.use(cors()); // tem que ativar antes das rotas da APP

Foi você me marcou como solucionado?????

Esbarrei... rs... Tem como "desolucionar"?? rs

Utilizando o Cors funcionou... Tirei o IF e funcionou corretamente.......

Tem não, mas tá tranquilo. O que eu quero que você fixe é que no curso de MEAN, todo acesso era no mesmo domínio, por isso o problema não acontece. Agora que temos duas aplicações separadas, entrou o CORS na jogada e a requisição de preflight gerada automaticamente pela sua app estava caindo no filtro de autenticação do seu server.

Perfeito! Mágica né? É por isso que eu uso esse cara! Ele deve colocar um middleware no meio que faz esse if para você.

Tudo tranquilo meu aluno?

Entendi... Muito obrigado pela ajuda...

Só depois me dá um OK para ver se essa dica ta certinha com base nesse post.

https://cursos.alura.com.br/course/vue-parte2/task/25540

Mais uma para os alunos!

A dica que você colocou no curso funciona, porem para precisa utilizar o Cors no server para funcionar corretamente.

Sem o Cors vai precisar daquela famigerado "IF".

Com o Cors esta funcionando bonito....

Até semana que vem minha primeira aplicação Web estará em produção no cliente. :)

Valeu....