Como enviar autenticação básica com axios

107

Estou tentando implementar o código a seguir, mas algo não está funcionando. Aqui está o código:

  var session_url = 'http://api_address/api/session_endpoint';
  var username = 'user';
  var password = 'password';
  var credentials = btoa(username + ':' + password);
  var basicAuth = 'Basic ' + credentials;
  axios.post(session_url, {
    headers: { 'Authorization': + basicAuth }
  }).then(function(response) {
    console.log('Authenticated');
  }).catch(function(error) {
    console.log('Error on Authentication');
  });

Ele está retornando um erro 401. Quando faço isso com o Postman, há uma opção para definir a autenticação básica; se eu não preencher esses campos também retorna 401, mas se eu preencher, a solicitação é bem-sucedida.

Alguma ideia do que estou fazendo de errado?

Aqui está parte da documentação da API sobre como implementar isso:

Este serviço usa informações de autenticação básica no cabeçalho para estabelecer uma sessão de usuário. As credenciais são validadas no servidor. Usar este serviço da web criará uma sessão com as credenciais do usuário passadas e retornará um JSESSIONID. Este JSESSIONID pode ser usado nas solicitações subsequentes para fazer chamadas de serviço da web. *

Emmanuel
fonte

Respostas:

152

Existe um parâmetro "auth" para autenticação básica:

auth: {
  username: 'janedoe',
  password: 's00pers3cret'
}

Fonte / Documentos: https://github.com/mzabriskie/axios

Exemplo:

await axios.post(session_url, {}, {
  auth: {
    username: uname,
    password: pass
  }
});
Luschn
fonte
4
Olá, como posso definir isso em todas as chamadas de axios? Preciso adicionar autenticação básica a todas as chamadas de Ajax. axios.defaults.auth = {nome de usuário: 'dd', senha: '##'} isso não está funcionando para mim.
hkg328 de
aliás, você também pode escrever um invólucro em torno de axios para esse tipo de coisas
luschn
Eu fiz um invólucro para isso. mas essa api me dá o erro 401
hkg328 de
1
@ hkg328 você precisa codificar a string username: password para base64 se quiser definir manualmente o cabeçalho. algo como importar btoa de 'btoa-lite'; token = btoa (nome de usuário + ':' + senha); em seguida, defina o cabeçalho como 'Básico' + token;
Shrumm
54

O motivo pelo qual o código em sua pergunta não autentica é porque você está enviando a autenticação no objeto de dados, não na configuração, que irá colocá-la nos cabeçalhos. De acordo com os documentos axios , o alias do método de solicitação parapost é:

axios.post (url [, dados [, config]])

Portanto, para que seu código funcione, você precisa enviar um objeto vazio para dados:

var session_url = 'http://api_address/api/session_endpoint';
var username = 'user';
var password = 'password';
var basicAuth = 'Basic ' + btoa(username + ':' + password);
axios.post(session_url, {}, {
  headers: { 'Authorization': + basicAuth }
}).then(function(response) {
  console.log('Authenticated');
}).catch(function(error) {
  console.log('Error on Authentication');
});

O mesmo é verdade para usar o parâmetro auth mencionado por @luschn. O código a seguir é equivalente, mas usa o parâmetro auth (e também passa um objeto de dados vazio):

var session_url = 'http://api_address/api/session_endpoint';
var uname = 'user';
var pass = 'password';
axios.post(session_url, {}, {
  auth: {
    username: uname,
    password: pass
  }
}).then(function(response) {
  console.log('Authenticated');
}).catch(function(error) {
  console.log('Error on Authentication');
});
Pillravi
fonte
1
ISTO
AJUDOU
1
Esta deve ser a resposta aceita. A resposta aceita é apenas uma duplicata da documentação.
Sinister Beard
5

Por alguns motivos, esse problema simples está bloqueando muitos desenvolvedores. Lutei por muitas horas com essa coisa simples. Este problema tem tantas dimensões:

  1. CORS (se você estiver usando um front-end e back-end em diferentes domínios e portas.
  2. Configuração de Backend CORS
  3. Configuração de autenticação básica do Axios

CORS

Minha configuração para desenvolvimento é com um aplicativo vuejs webpack rodando em localhost: 8081 e um aplicativo Spring Boot rodando em localhost: 8080. Portanto, ao tentar chamar a API rest do front-end, não há como o navegador me deixar receber uma resposta do back-end do Spring sem as configurações CORS adequadas. O CORS pode ser usado para relaxar a proteção Cross Domain Script (XSS) que os navegadores modernos possuem. Pelo que entendi, os navegadores estão protegendo seu SPA de ser um ataque de um XSS. Claro, algumas respostas no StackOverflow sugeriram adicionar um plug-in chrome para desabilitar a proteção XSS, mas isso realmente funciona E se fosse, apenas empurraria o problema inevitável para mais tarde.

Configuração de back-end CORS

Veja como você deve configurar o CORS em seu aplicativo Spring Boot:

Adicione uma classe CorsFilter para adicionar cabeçalhos adequados na resposta a uma solicitação do cliente. Access-Control-Allow-Origin e Access-Control-Allow-Headers são os itens mais importantes para autenticação básica.

    public class CorsFilter implements Filter {

...
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
        **response.setHeader("Access-Control-Allow-Headers", "authorization, Content-Type");**
        response.setHeader("Access-Control-Max-Age", "3600");

        filterChain.doFilter(servletRequest, servletResponse);

    }
...
}

Adicione uma classe de configuração que estende Spring WebSecurityConfigurationAdapter. Nesta aula, você injetará seu filtro CORS:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
    @Bean
    CorsFilter corsFilter() {
        CorsFilter filter = new CorsFilter();
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
          .csrf()
          .disable()
          .authorizeRequests()
          .antMatchers("/api/login")
          .permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .httpBasic()
          .authenticationEntryPoint(authenticationEntryPoint)
          .and()
          .authenticationProvider(getProvider());
    }
...
}

Você não precisa colocar nada relacionado ao CORS em seu controlador.

A parte dianteira

Agora, no front-end, você precisa criar sua consulta axios com o cabeçalho Authorization:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
    <p>{{ status }}</p>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            status: ''
        },
        created: function () {
            this.getBackendResource();
        },
        methods: {
            getBackendResource: function () {
                this.status = 'Loading...';
                var vm = this;
                var user = "aUserName";
                var pass = "aPassword";
                var url = 'http://localhost:8080/api/resource';

                var authorizationBasic = window.btoa(user + ':' + pass);
                var config = {
                    "headers": {
                        "Authorization": "Basic " + authorizationBasic
                    }
                };
                axios.get(url, config)
                    .then(function (response) {
                        vm.status = response.data[0];
                    })
                    .catch(function (error) {
                        vm.status = 'An error occured.' + error;
                    })
            }
        }
    })
</script>
</body>
</html>

Espero que isto ajude.

Erick Audet
fonte
pergunta noob CORS, isso só é usado no desenvolvimento, certo?
Len Joseph
Não, está também e principalmente em produção.
Erick Audet de
3

Um exemplo (axios_example.js) usando Axios em Node.js:

const axios = require('axios');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;

app.get('/search', function(req, res) {
    let query = req.query.queryStr;
    let url = `https://your.service.org?query=${query}`;

    axios({
        method:'get',
        url,
        auth: {
            username: 'xxxxxxxxxxxxx',
            password: 'xxxxxxxxxxxxx'
        }
    })
    .then(function (response) {
        res.send(JSON.stringify(response.data));
    })
    .catch(function (error) {
        console.log(error);
    });
});

var server = app.listen(port);

Certifique-se de que no diretório do seu projeto:

npm init
npm install express
npm install axios
node axios_example.js

Você pode então testar a API REST Node.js usando seu navegador em: http://localhost:5000/search?queryStr=xxxxxxxxx

Ref: https://github.com/axios/axios

Yuci
fonte
3

A solução dada por luschn e pillravi funciona bem a menos que você receba um Strict-Transport-Security cabeçalho na resposta.

Adicionar withCredentials: true resolverá esse problema.

  axios.post(session_url, {
    withCredentials: true,
    headers: {
      "Accept": "application/json",
      "Content-Type": "application/json"
    }
  },{
    auth: {
      username: "USERNAME",
      password: "PASSWORD"
  }}).then(function(response) {
    console.log('Authenticated');
  }).catch(function(error) {
    console.log('Error on Authentication');
  });
Leonard Saers
fonte