web-dev-qa-db-ja.com

Firebase Functions HTTPS 403 Forbidden

NodeおよびExpressを使用してFirebase HTTPイベント関数を作成しました。関数は機能していますが、クライアント側で関数を呼び出すと403 Forbidden。この関数を初めて呼び出したとき、Googleアカウントでサインインするように求められました。 Firebaseで使用しているのと同じアカウントでサインインしましたが、関数を呼び出すと次のようになりました。

403エラーのスクリーンショット

Googleクラウドプラットフォームでの使用の役割を確認したところ、関数を呼び出す権限はallUsersに設定されています。 Firebase CLIでログアウトしてから再度ログインしました。

こちらがindex.jsはfunctionsフォルダーにあります。

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

ここに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>

これがfirebase.jsonです。

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

私は試しましたが、これまでオンラインで見つけたすべての可能な解決策を使い果たしました。

7

これは、クラウド機能のHTTPリクエストとクラウド機能イベントへのアクセス許可に関係しているため、クラウド機能のIAM権限を編集する必要があります。

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

3
BadMask121

コードは、次の行のCloud Function _app1_としてExpressアプリケーションをエクスポートします。

_exports.app1 = functions.https.onRequest(app);
_

スクリーンショットで、存在しないapp Cloud Functionにアクセスしようとしましたが、代わりに_403 Forbidden_応答が返されました。

これは、クライアントから呼び出す正しいURLが

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

(または、エクスポートの名前をappに変更できます)

ソースコードをよく見て、次の行も削除する必要があります。コードをテストする場合は、代わりに_firebase serve_を使用します。

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

次の行では、ボディパーサーも2回注入しています。

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

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

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

あなたのコードでは、あなたも持っています:

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

Cloud Functionハンドラー(コード)がend()redirect()またはsend()を呼び出すとすぐに、Cloud Functionが許可されるため、これはCloud Functionには無効ですいつでも停止されるため、メールが送信されることはありません。これを修正するには、ファイルを最後に送信する必要があります。

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

私の最後の観察は、エラーはサーバーに存在しないPublicフォルダーが原因である可能性があるということです。 sendFile呼び出しに基づいて、デプロイされた関数が「パブリック」フォルダーを使用できることを期待していますが、functionsフォルダー内にないため、コードと共にデプロイされません。

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

このファイルは_your-domain.com/bedankt.html_からもアクセスできるため、リダイレクトします。代わりにこのファイルのHTMLコンテンツを送信したい場合は、デプロイされたfunctionsディレクトリ内に移動してください。

_res.redirect('/bedankt.html')
_

Firebaseホスティングの背後でExpress関数を使用しようとしているように見えるため、_index.js_ファイルを次のようにトリミングできます。

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

_firebase.json_ファイルを次のように更新する必要があります。

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

この構成では、最初にPublicディレクトリで一致するファイルを見つけようとします。一致が見つからない場合は、リクエストされたパスが_/api_で始まるかどうかをチェックし、そうである場合はCloud Functionを起動します。それでも一致が見つからない場合は、404ページ(または、存在しない場合は組み込みのページ)が表示されます。

2
samthecodingman