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

Problema ao realizar autenticação com react utilizando o axios

Boa tarde pessoal, sou iniciante em react e estou com o seguinte problema, ao tentar realizar a autenticação utilizando o axios, simplesmente o token não chega ao meu backend, não sei se pode ser um problema de cors ou com a configuração de como estou fazendo a chamada com o axios.

Aparentemente a parte do backend está correta, já testei utilizando o Postman.

No meu frontend, tenho o arquivo api.js onde crio uma instância de axios, e já coloco minha configuração:

const token = localStorage.getItem('auth-token')
//axios.create([config])
const api = axios.create({
    baseURL: "http://localhost:5000",
    headers: {'Authorization': `Bearer ${token}`}
});

E no meu componente eu faço a chamada:

api(baseUrl).then(resp => {
    this.setState({ list: resp.data.resellers })
}).catch(error => {
    console.log(error)
})

Essa parte do código eu verifico se existe o header authorization, caso contrario retorna erro, e no caso está caindo ai, pois não chega authorization com o token:

const authHeader = req.headers.authorization
if (!authHeader){
    return res.status(401).send({ error: 'No token provided' })
}

Não sei se está confuso minha descrição, qualquer coisa posso colocar no github o código.

Obrigado.

7 respostas

O middleware para validar o token me parece correto mas a chamada do Axios me parece com problema, eu não identifico para a rota que você quer acessar da sua api. Tente a seguinte alteração.

api.js

import axios from "axios";
const api = axios.create({
    baseURL: "http://localhost:5000"
});
export default api;

componente

import api from "./api";
export default class MeuComponente extends React.Component {
    componentDidMount() {
        const token = localStorage.getItem('auth-token');
        var config = {
        headers: { Authorization: "bearer " + token }
        };
        api.get("/minha_rota", {}, config).then(resp => {
            this.setState({ list: resp.data.resellers })
        }).catch(error => {
            console.log(error)
        })
    }

}

Olá Daniel, obrigado pela a ajuda, então tentei essa sua solução, mas também não deu certo, continua o mesmo erro.

Estou seguindo os mesmos passos da documentação, mas simplesmente o cabeçalho authorization não chega com a requisição.

Lá no middleware eu dou um console.log, desta forma:

const authHeader = req.headers.authorization
console.log(req.headers)
if (!authHeader){//se não tiver um authHeader
    console.log('No token provided')
    return res.status(401).send({ error: 'No token provided' })
}

E retorna o seguinte resultado:

{ 
    host: 'localhost:5000',
    connection: 'keep-alive',
    pragma: 'no-cache',
    'cache-control': 'no-cache',
    'access-control-request-method': 'GET',
    origin: 'http://localhost:3000',
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36',
    'access-control-request-headers': 'authorization',
    accept: '*/*',
    referer: 'http://localhost:3000/reseller',
    'accept-encoding': 'gzip, deflate, br',
    'accept-language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7' }

Se poder dar uma olhada no código que coloquei no github, esse é meu componente, segue o link: https://github.com/LeonardoCamargo31/agro-rec/blob/master/frontend/src/reseller/reseller.jsx

Pelo que eu vi do seu link, o "resp.data.resellers" aparece na função getUpdatedList(), mas nela não tem a alteração que eu sugeri. Tente alterar para ficar desta forma:

getUpdatedList() {
    //axios.get('/reseller')
    const token = localStorage.getItem('auth-token');
    const config = {
        headers: {
          'Authorization': 'Bearer ' + token,
          'Content-Type': 'application/json',
          'Accept': 'application/json'
        }
      }

    //Rota - parametros - configuracoes
    api.get('/reseller', {}, config).then(resp => {
        this.setState({ list: resp.data.resellers })
    }).catch(error => {
        console.log(error)
    })
}

Aqui mais informações sobre como fazer requisições com Axios

http://codeheaven.io/how-to-use-axios-as-your-http-client-pt/

Feita a alteração, e segue com o mesmo erro :(

getUpdatedList() {
    //axios.get('/reseller')
    const token = localStorage.getItem('auth-token');
    const config = {
        headers: {
            'Authorization': 'Bearer ' + token,
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        }
    }

    api.get('/reseller', {}, config).then(resp => {
        this.setState({ list: resp.data.resellers })
    }).catch(error => {
        console.log(error)
    })
}

Existe uma outra forma de fazer, que seria esta:

getUpdatedList() {
    const token = localStorage.getItem('auth-token');
 api.defaults.headers.common['Authorization'] = 'Bearer ' + token;
    api.get('/reseller').then(resp => {
        this.setState({ list: resp.data.resellers })
    }).catch(error => {
        console.log(error)
    })
}

Uma observação: No seu backend, precisa dar uma olhada se você está permitindo os cabeçalhos. No meu caso, somente funcionou com esta configuração (exemplo). Se o erro persistir, pode ser isso.

const express = require('express');
const app = express();         
const bodyParser = require('body-parser');
const port = 3001; //Teste
app.use(bodyParser.json());
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "OPTIONS,Accept,Authorization, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Header");
  next();
});
//Resto da programação, rotas, etc...
app.listen(port);

Então Daniel o problema parece ser o CORS, fiz a alteração com a sua sugestão, e no console do navegador, ele exibe o seguinte erro:

Access to XMLHttpRequest at 'http://localhost:5000/reseller' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

Mas dentro da minha rota, eu consigo pegar a requisição, se eu eu der um console.log(), como no código abaixo:

//router.use(authMiddleware);

router.get('/', async (req, res) => {
    console.log(req.headers.authorization)
    try {
        const resellers = await Reseller.find();
        return res.send({ resellers });
    } catch (err) {
        return res.status(400).send({ error: 'Error loading resellers' });
    }
})

Ele me retorna o token corretamente:

Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVjN...
solução!

Então Daniel, obrigado pela ajuda, consegui resolvi da seguinte forma:

Achei um problema semelhante: https://stackoverflow.com/questions/52047548/response-for-preflight-does-not-have-http-ok-status-in-angular

Então deixei de ultilizar meu middleware cors, e fiz a instalação do pacote cors

npm install cors
var express = require('express')
var cors = require('cors')
var app = express()

app.use(cors())

E problema resolvido!