Comment envoyer une authentification de base avec axios

107

J'essaye d'implémenter le code suivant, mais quelque chose ne fonctionne pas. Voici le code:

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

Il renvoie une erreur 401. Lorsque je le fais avec Postman, il y a une option pour définir l'authentification de base; si je ne remplis pas ces champs, il renvoie également 401, mais si je le fais, la demande est réussie.

Des idées sur ce que je fais mal?

Voici une partie de la documentation de l'API sur la façon de l'implémenter:

Ce service utilise les informations d'authentification de base dans l'en-tête pour établir une session utilisateur. Les informations d'identification sont validées par rapport au serveur. L'utilisation de ce service Web créera une session avec les informations d'identification de l'utilisateur transmises et retournera un JSESSIONID. Ce JSESSIONID peut être utilisé dans les demandes suivantes pour effectuer des appels de service Web. *

Emmanuel
la source

Réponses:

153

Il existe un paramètre "auth" pour l'authentification de base:

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

Source / Documents: https://github.com/mzabriskie/axios

Exemple:

await axios.post(session_url, {}, {
  auth: {
    username: uname,
    password: pass
  }
});
Luschn
la source
4
bonjour, comment puis-je définir cela dans tous les appels axios? J'ai besoin d'ajouter l'authentification de base à tous les appels ajax. axios.defaults.auth = {nom d'utilisateur: 'dd', mot de passe: '##'} cela ne fonctionne pas pour moi.
hkg328
btw, vous pouvez également écrire un wrapper autour d'axios pour ce genre de choses
luschn
J'ai fait un emballage pour ça. mais cette API me donne une erreur 401
hkg328
1
@ hkg328, vous devez encoder la chaîne username: password en base64 si vous souhaitez définir manuellement l'en-tête. quelque chose comme importer btoa depuis 'btoa-lite'; token = btoa (nom d'utilisateur + ':' + mot de passe); puis définissez l'en-tête sur «Basic» + token;
shrumm
54

La raison pour laquelle le code de votre question ne s'authentifie pas est que vous envoyez l'authentification dans l'objet de données, pas dans la configuration, ce qui la mettra dans les en-têtes. Selon la documentation axios , l' alias de la méthode de requête pour postest:

axios.post (url [, données [, config]])

Par conséquent, pour que votre code fonctionne, vous devez envoyer un objet vide pour les données:

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

Il en va de même pour l'utilisation du paramètre auth mentionné par @luschn. Le code suivant est équivalent, mais utilise le paramètre auth à la place (et transmet également un objet de données vide):

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
la source
1
CECI A AIDÉ, MERCI
superrcoop
1
Cela devrait être la réponse acceptée. La réponse acceptée n'est qu'un double de la documentation.
Sinister Beard
5

Pour certaines raisons, ce simple problème bloque de nombreux développeurs. J'ai lutté pendant de nombreuses heures avec cette chose simple. Ce problème autant de dimensions:

  1. CORS (si vous utilisez un frontend et un backend sur différents domaines et ports.
  2. Configuration CORS du backend
  3. Configuration de l'authentification de base d'Axios

CORS

Ma configuration pour le développement est avec une application webpack vuejs s'exécutant sur localhost: 8081 et une application de démarrage de printemps s'exécutant sur localhost: 8080. Ainsi, lorsque vous essayez d'appeler l'API rest depuis le frontend, il n'y a aucun moyen que le navigateur me permette de recevoir une réponse du backend Spring sans les paramètres CORS appropriés. CORS peut être utilisé pour assouplir la protection XSS (Cross Domain Script) offerte par les navigateurs modernes. Si je comprends bien, les navigateurs protègent votre SPA contre une attaque par un XSS. Bien sûr, certaines réponses sur StackOverflow suggéraient d'ajouter un plugin chrome pour désactiver la protection XSS, mais cela fonctionne vraiment ET si c'était le cas, cela ne ferait que pousser l'inévitable problème pour plus tard.

Configuration du backend CORS

Voici comment configurer CORS dans votre application Spring Boot:

Ajoutez une classe CorsFilter pour ajouter les en-têtes appropriés dans la réponse à une demande client. Access-Control-Allow-Origin et Access-Control-Allow-Headers sont la chose la plus importante à avoir pour l'authentification de base.

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

    }
...
}

Ajoutez une classe de configuration qui étend Spring WebSecurityConfigurationAdapter. Dans cette classe, vous injecterez votre filtre 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());
    }
...
}

Vous n'avez rien à mettre en rapport avec CORS dans votre contrôleur.

L'extrémité avant

Maintenant, dans le frontend, vous devez créer votre requête axios avec l'en-tête 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>

J'espère que cela t'aides.

Erick Audet
la source
noob question CORS, ce n'est utilisé que dans le développement, non?
Len Joseph
Non, c'est aussi et surtout en production.
Erick Audet
3

Un exemple (axios_example.js) utilisant Axios dans 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);

Assurez-vous que dans le répertoire de votre projet vous faites:

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

Vous pouvez ensuite tester l'API REST Node.js à l'aide de votre navigateur à l'adresse: http://localhost:5000/search?queryStr=xxxxxxxxx

Réf: https://github.com/axios/axios

Yuci
la source
3

La solution donnée par luschn et pillravi fonctionne bien sauf si vous recevez un en - tête Strict-Transport-Security dans la réponse.

L'ajout de withCredentials: true résoudra ce problème.

  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
la source