You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase AppCheck+reCAPTCHA Enterprise令牌验证失败求助

问题:Firebase AppCheck搭配reCAPTCHA Enterprise验证返回Unauthorized

我正在开发一款支持用户创建Docker容器的应用,采用Firebase AppCheck搭配reCAPTCHA Enterprise保护API。前端已成功将令牌发送至后端(后端可通过console.log获取令牌),但验证过程无错误提示,仅返回“Unauthorized”。

相关代码

createcontainer.html

<!DOCTYPE html>
<html>
<head>
    <title>Create Instance</title>
    <link rel="stylesheet" href="page.css">
    <script type="module" src="check.js" defer></script>
    <script type="module" src="script.js" defer></script>
</head>
<body>
    <form>
        <h1>Create Gaming Instance</h1>
        <label for="width">Width:</label>
        <input type="text" id="width" required><br><br>
        <label for="height">Height:</label>
        <input type="text" id="height" required><br><br>
        <label for="user">User:</label>
        <input type="text" id="user" required><br><br>
        <label for="password">Password:</label>
        <input type="text" id="password" required><br><br>
        <button id="submitForm" type="submit">Submit</button>
    </form>
</body>
</html>

script.js

import { initializeApp } from "https://www.gstatic.com/firebasejs/10.14.0/firebase-app.js";
import { initializeAppCheck, ReCaptchaEnterpriseProvider, getToken } from "https://www.gstatic.com/firebasejs/10.14.0/firebase-app-check.js";

const firebaseConfig = {
    apiKey: "xxxxxxxx",
    authDomain: "reyv-a8452.firebaseapp.com",
    projectId: "reyv-a8452",
    storageBucket: "reyv-a8452.appspot.com",
    messagingSenderId: "174731893649",
    appId: "1:174731893649:web:685b864d27176334b4d830"
};

const app = initializeApp(firebaseConfig);
const appCheck = initializeAppCheck(app, {
    provider: new ReCaptchaEnterpriseProvider("xxxxxxxxxx"),
    isTokenAutoRefreshEnabled: true // Set to true to allow auto-refresh.
});

const submitForm = document.getElementById('submitForm');
submitForm.addEventListener("click", async function (event) {
    event.preventDefault()
    var width = document.getElementById("width").value;
    var height = document.getElementById("height").value;
    var user = document.getElementById("user").value;
    var password = document.getElementById("password").value;
    let appCheckTokenResponse;
    appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ false)

    // Send data to the backend
    fetch('/process', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-Firebase-AppCheck': appCheckTokenResponse.token
        },
        body: JSON.stringify({ width: width, height: height, user: user, password: password })
    })
    .then(response => response.json())
    .then(data => {
        // Handle the response from the backend
        data = JSON.stringify({ data: data })
        data = data.replace('{"data":{"message":"', '')
        data = data.replace('"}}', '')
        window.location.href = data;
    })
})

server.js

const fs = require("fs");
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
var Docker = require('dockerode');
var docker = new Docker({host: 'xxxxxx', port: xxxxx});
var portnumber = "8080"
var admin = require("firebase-admin");
var serviceAccount = require("./xxxxxxxxx");

admin.initializeApp({
    credential: admin.credential.cert(serviceAccount)
  });

function createdockercontainer(width, height, portnumber, user, password) {
    docker.createContainer({Image: 'selkies', Tty: false, HostConfig: {ShmSize: 1073741824, NetworkMode: "host", Privileged: true}, Cmd: [width, height, portnumber, user, password]}, function(err,container){
        container.start();
    })
}

const incrementNr = (nr) => {
    const [nrDigits] = /\d*$/.exec(nr);
    const next = '' + (+nrDigits + 1);
    const nextNr = nr.slice(0, nr.length - Math.min(next.length, nrDigits.length)) + next;
    return nextNr;
  };

// Middleware
app.use(bodyParser.json());
const appCheckVerification = async (req, res, next) => {
  const appCheckToken = req.header('X-Firebase-AppCheck');
  console.log(appCheckToken)

  if (!appCheckToken) {
      res.status(401);
      return next("Unauthorized");
  }

  try {
      const appCheckClaims = await getAppCheck().verifyToken(appCheckToken);

      // If verifyToken() succeeds, continue with the next middleware
      // function in the stack.
      return next();
  } catch (err) {
      res.status(401);
      return next("Unauthorized");
  }
}

// Process the form data
app.post('/process', [appCheckVerification], (req, res) => {
    const width = req.body.width;
    const height = req.body.height;
    const user = req.body.user;
    const password = req.body.password;

    // Process the data or perform any backend tasks
    // ...

    // Return a response back to the frontend
    portnumber = incrementNr(portnumber)
    createdockercontainer(width, height, portnumber, user, password)
    res.json({
        message: 'https://reyv.org'
    });
});

// Start the server
const port = 3000;
app.use(express.static('public'))
app.listen(port, () => {
    console.log(`Server started on port ${port}`);
});

额外信息

在Firebase控制台添加reCAPTCHA Enterprise密钥时显示红色标记。


内容的提问来源于stack exchange,提问作者doctor1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 07:05:59