Cómo enviar autenticación básica con axios

107

Estoy intentando implementar el siguiente código, pero algo no funciona. Aquí está el 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');
  });

Devuelve un error 401. Cuando lo hago con Postman hay una opción para configurar la autenticación básica; si no completo esos campos, también devuelve 401, pero si lo hago, la solicitud es exitosa.

¿Alguna idea de lo que estoy haciendo mal?

Aquí hay parte de los documentos de la API sobre cómo implementar esto:

Este servicio utiliza información de autenticación básica en el encabezado para establecer una sesión de usuario. Las credenciales se validan con el servidor. El uso de este servicio web creará una sesión con las credenciales de usuario pasadas y devolverá un JSESSIONID. Este JSESSIONID se puede utilizar en las solicitudes posteriores para realizar llamadas al servicio web. *

Emmanuel
fuente

Respuestas:

153

Hay un parámetro "auth" para la autenticación básica:

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

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

Ejemplo:

await axios.post(session_url, {}, {
  auth: {
    username: uname,
    password: pass
  }
});
luschn
fuente
4
hola, ¿cómo puedo configurar eso en todas las llamadas de axios? Necesito agregar autenticación básica a todas las llamadas ajax. axios.defaults.auth = {nombre de usuario: 'dd', contraseña: '##'} esto no me funciona.
hkg328
por cierto, también puedes escribir un resumen sobre axios para ese tipo de cosas
luschn
Hice una envoltura para eso. pero esa API me da un error 401
hkg328
1
@ hkg328 necesita codificar la cadena username: password en base64 si desea configurar manualmente el encabezado. algo como importar btoa de 'btoa-lite'; token = btoa (nombre de usuario + ':' + contraseña); luego establezca el encabezado en 'Básico' + token;
Shrumm
54

La razón por la que el código en su pregunta no se autentica es porque está enviando la autenticación en el objeto de datos, no en la configuración, que lo colocará en los encabezados. Por los documentos Axios , el alias método de petición para postes:

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

Por lo tanto, para que su código funcione, debe enviar un objeto vacío para los datos:

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');
});

Lo mismo es cierto para el uso del parámetro auth mencionado por @luschn. El siguiente código es equivalente, pero usa el parámetro auth en su lugar (y también pasa un objeto de datos vacío):

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
fuente
1
ESTO AYUDÓ, GRACIAS
superrcoop
1
Esta debería ser la respuesta aceptada. La respuesta aceptada es solo un duplicado de la documentación.
Sinister Beard
5

Por algunas razones, este simple problema está bloqueando a muchos desarrolladores. Luché durante muchas horas con esta simple cosa. Este problema tantas dimensiones:

  1. CORS (si está utilizando un frontend y un backend en diferentes dominios y puertos.
  2. Configuración de CORS backend
  3. Configuración de autenticación básica de Axios

CORS

Mi configuración para el desarrollo es con una aplicación de paquete web vuejs que se ejecuta en localhost: 8081 y una aplicación de arranque de primavera que se ejecuta en localhost: 8080. Entonces, cuando intento llamar a la API de descanso desde el frontend, no hay forma de que el navegador me permita recibir una respuesta del backend de primavera sin la configuración CORS adecuada. CORS se puede utilizar para relajar la protección Cross Domain Script (XSS) que tienen los navegadores modernos. Según tengo entendido, los navegadores protegen su SPA de un ataque de un XSS. Por supuesto, algunas respuestas en StackOverflow sugirieron agregar un complemento de Chrome para deshabilitar la protección XSS, pero esto realmente funciona Y si lo fuera, solo empujaría el problema inevitable para más adelante.

Configuración de backend CORS

Así es como debe configurar CORS en su aplicación de arranque de primavera:

Agregue una clase CorsFilter para agregar encabezados adecuados en la respuesta a una solicitud de cliente. Access-Control-Allow-Origin y Access-Control-Allow-Headers son lo más importante para la autenticación 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);

    }
...
}

Agregue una clase de configuración que amplíe Spring WebSecurityConfigurationAdapter. En esta clase inyectarás tu 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());
    }
...
}

No tiene que poner nada relacionado con CORS en su controlador.

Interfaz

Ahora, en la interfaz, debe crear su consulta axios con el encabezado Autorización:

<!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 esto ayude.

Erick Audet
fuente
Pregunta de novato CORS, esto solo se usa en desarrollo, ¿verdad?
Len Joseph
No, también y principalmente en producción.
Erick Audet
3

Un ejemplo (axios_example.js) usando Axios en 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);

Asegúrese de que en el directorio de su proyecto lo haga:

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

Luego puede probar la API REST de Node.js usando su navegador en: http://localhost:5000/search?queryStr=xxxxxxxxx

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

Yuci
fuente
3

La solución dada por luschn y pillravi funciona bien a menos que reciba un Strict-Transport-Security encabezado en la respuesta.

Agregar withCredentials: true resolverá ese 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
fuente