Firebase 功能 HTTPS 403 禁止

Posted

技术标签:

【中文标题】Firebase 功能 HTTPS 403 禁止【英文标题】:Firebase Functions HTTPS 403 Forbidden 【发布时间】:2020-05-30 21:26:00 【问题描述】:

我使用 Node 和 Express 构建了一个 Firebase HTTP 事件函数。该函数正在运行,但是当我在客户端调用该函数时,我得到403 Forbidden。第一次调用该函数时,我被要求使用 Google 帐户登录。我使用与 Firebase 相同的帐户登录,但是当我调用我得到的函数时:

Screenshot of 403 error

我查看了谷歌云平台上的使用角色,调用该功能的权限设置为allUsers。我在 Firebase CLI 中退出并重新登录。

这是函数文件夹中的index.js

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: 'gietvloermakers@gmail.com',
      pass: 'Gietvloermakers2020!'
    
  );

  var mailOptions = 
    from: 'gietvloermakers@gmail.com',
    to: 'gvbeusekom84@hotmail.com',
    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"
    ]
  

我试过了,但到目前为止我已经用尽了我在网上找到的所有可能的解决方案。

【问题讨论】:

【参考方案1】:

如果您收到如下所示的 403 禁止错误

错误:禁止您的客户端无权获取 URL /api/test 来自此服务器。

请按照以下步骤向所有用户授予访问权限。基本上这是为了允许未经身份验证的客户端访问您的 api 端点。

转到https://console.cloud.google.com/functions/list 选择您要公开访问的功能 点击权限 点击添加成员 输入 allUsers 选择角色 Cloud Functions -> Cloud Functions Invoker 保存

就是这样,现在测试你的 api。

【讨论】:

【参考方案2】:

遇到了同样的问题(被要求使用我的 Google 帐户登录,然后被拒绝访问)。事实证明,功能目前在默认区域之外不起作用。就我而言,我必须在这里进行更改:

 exports.app = functions
  .region('europe-west6') // does not work, delete this line
  .https.onRequest(app);

【讨论】:

【参考方案3】:

这与对您的云函数 http 请求和云函数事件的权限访问有关,您需要编辑您的云函数 IAM 权限。

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

【讨论】:

感谢您回答@BadMask121!几周前,我确实通过更改 IAM 权限解决了这个问题。【参考方案4】:

我最近遇到了这个。事实证明,截至 2020 年 1 月 15 日,新功能默认需要身份验证。

详情请见the docs here。

解决方案是在 Google Cloud Console 的 Cloud Functions 页面中手动为 allUsers 用户添加 Cloud Functions Invoker 权限。

【讨论】:

在我的例子中,Cloud Functions Invoker 作为默认添加(没有我做),但它仍然没有工作。 对我来说,默认添加了规则,仍然无法访问该功能。 Google firebase 需要处理他们的文档 非常感谢,此文档应在 Firebase 函数文档中链接/引用。【参考方案5】:

您的代码在此行将 express 应用程序导出为 Cloud Function app1

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

在您的屏幕截图中,您尝试访问不存在的 app 云函数,而不是导致 403 Forbidden 响应。

这意味着从您的客户端调用的正确 URL 是

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

(或者您可以将导出的名称更改为app

仔细查看您的源代码,您还应该删除以下行。如果你想测试你的代码,你可以改用firebase serve

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

在以下几行中,您还注入了两次正文解析器。

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 */
)

这对云函数无效,因为一旦云函数处理程序(您的代码)调用end()redirect()send(),云函数就可以随时终止,这意味着您的电子邮件可能永远不会被发送。要解决此问题,您需要最后发送文件。

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

我最后的观察是,该错误可能是由服务器上不存在的文件夹 Public 引起的。根据您的sendFile 调用,您期望文件夹“Public”可用于您部署的函数,但由于它不在functions 文件夹内,因此不会与您的代码一起部署。

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

因为这个文件也可以通过your-domain.com/bedankt.html 访问,我们将重定向到它。如果您想发送此文件的 HTML 内容,请将其移至部署的函数目录中。

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: 'gietvloermakers@gmail.com',
      pass: 'Gietvloermakers2020!'
    
  );

  var mailOptions = 
    from: 'gietvloermakers@gmail.com',
    to: 'gvbeusekom84@hotmail.com',
    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 开头,如果是,则启动您的云函数。如果仍然找不到匹配项,它将显示您的 404 页面(如果不存在,则显示内置页面)。

【讨论】:

感谢您的回复!当我第一次编写函数时,我将函数导出为ex​​ports.app = functions.https.onRequest(app);当我调用该函数时,它给了我同样的错误。我将函数名称更改为 app1 以查看发生了什么,但没有任何改变。我被要求再次登录谷歌帐户并在登录后收到相同的 403 错误。当我再次调用该函数时,它只是显示 Forbidden。 @GijsvanBeusekom 请参阅添加的文档。 感谢@samthecodingman 的所有指点。我实施了代码更改,现在出现无法发布错误。它说路径是/gietvloermakers/us-central1/api/api/app1。因为我今天想让网站上线,所以将 res.sendfile 更改为 res.send 并使用一些简单的 html 来获得可接受的产品。我仍然很好奇出了什么问题。 firebase.json 中的“rewritesource”是否在路径中创建了双 api? @GijsvanBeusekom 根据我可以看到的 GitHub 存储库,您仍然需要删除 app.use(express.static('Public'));(Firebase 托管将负责从公共提供文件)并且您应该能够使用 res.sendFile('./bedankt.html', root: __dirname)因为bedankt.html 在您的函数文件夹中。 我在上面的index.js 中也犯了一个错误,路由应该是/api/user,因为当从主机调用时,express 将通过https://gietvloermakers.nl/api/user 而不是我所期望的。这确实意味着直接调用它会在http://us-central1-gietvloermakers.cloudfunctions.net/[EXPORT_NAME]/api/user 完成(如果导出为api 将意味着它将在http://us-central1-gietvloermakers.cloudfunctions.net/api/api/user

以上是关于Firebase 功能 HTTPS 403 禁止的主要内容,如果未能解决你的问题,请参考以下文章

在家庭服务器上处理 Stripe 付款时出现禁止 (403) 错误

SendGrid 无法发送电子邮件、firebase 功能。 (代码:403)

仅在 https 上出现禁止的 403 错误,但 url http 工作正常

被 https 中 WCF 服务的“远程服务器返回错误:(403)禁止”所困扰

得到403禁止错误[重复]

403 客户端错误:禁止访问 url:https://ropsten.infura.io/v3/PROJECT_ID