web-dev-qa-db-fra.com

Fonctions Firebase HTTPS 403 interdit

J'ai créé une fonction d'événement HTTP Firebase avec Node et Express. La fonction fonctionne, mais lorsque j'appelle la fonction côté client, j'obtiens 403 Forbidden. La première fois que j'ai appelé la fonction, on m'a demandé de me connecter avec un compte Google. Je me suis connecté avec le même compte que j'utilise pour Firebase, mais lorsque j'ai appelé la fonction, j'ai obtenu:

Capture d'écran de l'erreur 4

J'ai examiné les rôles d'utilisation sur la plate-forme cloud de Google et l'autorisation d'appeler la fonction est définie sur allUsers. Je me suis déconnecté et je me suis reconnecté dans la CLI Firebase.

Voici la index.js dans le dossier des fonctions:

const functions = require('firebase-functions');
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const port = process.env.port || 5600
const nodemailer = require('nodemailer');

app.use(express.static('Public'));

app.use(bodyParser.urlencoded({ extended: true }));

const urlencodedParser = bodyParser.urlencoded({extended: true});

app.post("/api/user", urlencodedParser, (req, res) => {
  res.sendFile('../Public/bedankt.html', {root: __dirname})
  const persGegevens = req.body

  const string = JSON.stringify(persGegevens, (key, value) => {
    if (typeof value === "string"){
      return value.toUpperCase();
    } else {
      return value
    }
  }, 1);

  var transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
      user: '[email protected]',
      pass: 'Gietvloermakers2020!'
    }
  });

  var mailOptions = {
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Nieuwe bestelling op Gietvloermakers',
    html: string
  };

  transporter.sendMail(mailOptions, function(error, info){
    if (error) {
      console.log(error);
    } else {
      console.log('Email sent: ' + info.response);
    }
  });
});

exports.app1 = functions.https.onRequest(app);

app.listen(port);

console.log(port);

Voici le html:

<form id="controlleer-form" action="/api/user" method="post" enctype="application/x-www-form-urlencoded">
    <div class="controleer-div">
        <h2>Uw bestelling</h2>
        <p>Aantal m2</p>
        <input class="controle-input" type="text" name="aantalM2" id="aantalM2" readonly>
        <p>Kleur</p>
        <input class="controle-input" type="text" name="kleur" id="kleur" readonly>
        <p>Assistentie</p>
        <input class="controle-input" type="text" name="assistentie" id="assistentie" readonly>
        <p>Gereedschappen</p>
        <input class="controle-input" type="text" name="gereedschappen" id="gereedschappen" readonly>
        <p>Totale prijs</p>
        <input  class="controle-input" type="text" name="totale-prijs" id="totale-prijs" readonly>
        <a href="bestellen.html"><p id="andere-kleur">Bestelling aanpassen</p></a>
    </div>
    <div class="controleer-div">
        <h2>Uw gegevens</h2>
        <p>Voornaam</p>
        <input type="text" name="voornaam" placeholder="Voornaam">
        <p>Achternaam</p>
        <input type="text" name="Achternaam" placeholder="Achternaam">
        <p>Straatnaam en huisnummer</p>
        <input type="text" name="Achternaam" placeholder="Straatnaam en huisnummer">
        <p>Postcode</p>
        <input type="text" name="Achternaam" placeholder="Postcode">
        <p>Telefoonnummer</p>
        <input type="tel" name="telefoonnummer" placeholder="Telefoonnummer">
        <p>Emailadres</p>
        <input type="email" name="email" placeholder="Emailadres"><br>
        <input id="verzenden" type="submit"> 
    </div>
</form>

Voici le firebase.json:

{
  "hosting": {
    "public": "Public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [{
      "source": "**",
      "function": "app1"
    }]
  }
}

J'ai essayé mais j'ai épuisé toutes les solutions possibles que j'ai trouvées en ligne jusqu'à présent.

7
Gijs van Beusekom

Cela a à voir avec l'autorisation d'accès à vos demandes http de fonctions cloud et les événements de fonction cloud, vous devez modifier votre autorisation IAM de fonction cloud.

https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_function_invocation

3
BadMask121

Votre code exporte l'application express en tant que fonction Cloud app1 Sur cette ligne:

exports.app1 = functions.https.onRequest(app);

Dans votre capture d'écran, vous avez essayé d'accéder à la fonction cloud app inexistante, ce qui a entraîné la réponse 403 Forbidden.

Cela signifie que l'URL correcte à appeler depuis votre client est

http://us-central1-gietvloermakers.cloudfunctions.net/app1/api/user
                                                      ^^^^

(ou vous pouvez changer le nom de l'exportation en app)

En examinant de plus près votre code source, vous devez également supprimer les lignes suivantes. Si vous vouliez tester votre code, vous utiliseriez à la place firebase serve.

const port = process.env.port || 5600
/* ... */
app.listen(port);

Sur les lignes suivantes, vous injectez également l'analyseur corporel deux fois.

app.use(bodyParser.urlencoded({ extended: true })); // use this

const urlencodedParser = bodyParser.urlencoded({extended: true}); // or this, not both

app.post("/api/user", urlencodedParser, ...

Dans votre code, vous avez également:

app.post("/api/user", urlencodedParser, (req, res) => {
  res.sendFile('../Public/bedankt.html', {root: __dirname})
  /* do some other stuff */
})

Ceci n'est pas valide pour une fonction cloud, car dès que le gestionnaire de fonction cloud (votre code) appelle end(), redirect() ou send(), la fonction cloud est autorisée être résilié à tout moment, ce qui signifie que votre e-mail ne pourra jamais être envoyé. Pour résoudre ce problème, vous devez envoyer le fichier en dernier.

app.post("/api/user", urlencodedParser, (req, res) => {
  /* do some other stuff */
  res.sendFile('../Public/bedankt.html', {root: __dirname})
});

Ma dernière observation, c'est que l'erreur peut être causée par le dossier Public qui n'existe pas sur le serveur. En fonction de votre appel sendFile, vous vous attendez à ce que le dossier "Public" soit disponible pour votre fonction déployée, mais comme il ne se trouve pas dans le dossier functions, il ne sera pas déployé avec votre code.

res.sendFile('../Public/bedankt.html', {root: __dirname})

Comme ce fichier serait également accessible à your-domain.com/bedankt.html, Nous y redirigeons. Si vous souhaitez envoyer le contenu HTML de ce fichier à la place, déplacez-le dans votre répertoire de fonctions déployées.

res.redirect('/bedankt.html')

Comme vous semblez essayer d'utiliser votre fonction express derrière l'hébergement Firebase, nous pouvons découper votre fichier index.js Comme suit:

const functions = require('firebase-functions');
const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');

const apiApp = express();

apiApp.use(bodyParser.urlencoded({ extended: true }));

apiApp.post("/api/user", (req, res) => {
  const persGegevens = req.body

  const string = JSON.stringify(persGegevens, (key, value) => {
    if (typeof value === "string"){
      return value.toUpperCase();
    } else {
      return value
    }
  }, 1);

  var transporter = nodemailer.createTransport({
    service: 'gmail',
    auth: {
      user: '[email protected]',
      pass: 'Gietvloermakers2020!'
    }
  });

  var mailOptions = {
    from: '[email protected]',
    to: '[email protected]',
    subject: 'Nieuwe bestelling op Gietvloermakers',
    html: string
  };

  transporter.sendMail(mailOptions, function(error, info){
    if (error) {
      console.log(error);
      res.redirect('/bedankt.html?success=0');
    } else {
      console.log('Email sent: ' + info.response);
      res.redirect('/bedankt.html?success=1');
    }
  });  
});

// note rename to api
exports.api = functions.https.onRequest(apiApp);

qui nécessite la mise à jour de votre fichier firebase.json vers:

{
  "hosting": {
    "public": "Public",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [{
      "source": "/api/**",
      "function": "api"
    }]
  }
}

Cette configuration tentera d'abord de trouver un fichier correspondant dans votre répertoire Public. S'il ne trouve pas de correspondance, il vérifiera si le chemin demandé commence par /api Et si c'est le cas, lance votre fonction Cloud. S'il ne trouve toujours pas de correspondance, il affichera votre page 404 (ou celle intégrée si elle n'existe pas).

2
samthecodingman