Firebase Appcheck не проверяет токен

Вопрос или проблема

Я создаю приложение, в котором люди могут создавать контейнеры Docker. Я пытаюсь защитить свой API, используя Firebase App Check с reCAPTCHA Enterprise. Я отправляю токен с фронтенда на бэкэнд для проверки. Я знаю, что токен отправляется, так как могу вывести его в консоль, когда он доходит до бэкэнда, поэтому думаю, что это ошибка с проверкой. Код не показывает никаких ошибок, он просто говорит “Неавторизован”. Вот мой код.

createcontainer.html

<!DOCTYPE html>
<html>
<head>
    <title>Создать экземпляр</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>Создать игровой экземпляр</h1>
        <label for=""width>Ширина:</label>
        <input type="text" id="width" required><br><br>
        <label for="height">Высота:</label>
        <input type="text" id="height" required><br><br>
        <label for="user">Пользователь:</label>
        <input type="text" id="user" required><br><br>
        <label for="password">Пароль:</label>
        <input type="text" id="password" required><br><br>
        <button id="submitForm" type="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 // Установите в true, чтобы разрешить автоматическое обновление.
});

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)

    // Отправить данные на бэкэнд
    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 => {
        // Обработать ответ от бэкэнда
        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("Неавторизован");
  }

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

      // Если verifyToken() завершается успешно, продолжить с следующим middleware
      // функцией в стеке.
      return next();
  } catch (err) {
      res.status(401);
      return next("Неавторизован");
  }
}

// Обработка данных формы
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;

    // Обработать данные или выполнить любые задние задачи
    // ...

    // Вернуть ответ обратно на фронтенд
    portnumber = incrementNr(portnumber)
    createdockercontainer(width, height, portnumber, user, password)
    res.json({
        message: 'https://reyv.org'
    });
});

// Запустить сервер
const port = 3000;
app.use(express.static('public'))
app.listen(port, () => {
    console.log(`Сервер запущен на порту ${port}`);
});

Не уверен, связано ли это, но при добавлении ключа reCAPTCHA enterprise в консоль Firebase он показывает красное кольцо. Консоль Firebase

Ответ или решение

Проблема с верификацией токена Firebase App Check при использовании reCAPTCHA Enterprise

Ваша проблема с верификацией токена Firebase App Check может быть вызвана различными факторами. В данном ответе мы рассмотрим основные причины и предложим пути их устранения.

Причины возникновения проблемы

  1. Отсутствие токена: Вы уже упомянули, что токен успешно отправляется на бэкэнд, но стоит удостовериться, что он действительно присутствует в заголовках запроса. В вашем коде есть лог для вывода токена console.log(appCheckToken). Проверьте, что токен действительно отображается корректно на сервере.

  2. Неверная конфигурация:

    • Проверьте правильность настройки ключа reCAPTCHA Enterprise в консоли Firebase. Красное кольцо может указывать на неправильную настройку или отсутствие доступа. Убедитесь, что ключ активирован и имеет все необходимые разрешения.
    • Убедитесь, что вы используете тот же проект Firebase как на фронтенде, так и на бэкенде.
  3. Неправильная верификация токена:

    • В коде бэкенда вы обращаетесь к функции getAppCheck() для верификации токена. Убедитесь, что эта функция корректно инициализирует администраторскую библиотеку Firebase. Попробуйте импортировать и использовать admin.appCheck().

Рекомендации по решениям

1. Проверка настройки reCAPTCHA

Перейдите в консоль Firebase и убедитесь, что ключ reCAPTCHA Enterprise правильно настроен. Попробуйте сделать следующее:

  • Создайте новый ключ и убедитесь, что у него правильные доменные имена.
  • Проверьте, активирован ли ключ.

2. Источник токена

Убедитесь, что токены от клиента действительно сгенерированы и не истекли. Вы можете реализовать ручное обновление токена, установив forceRefresh = true в getToken(). Кроме того, следите за тем, чтобы на фронтенде не было ошибок в запросах, которые могли бы мешать получению токена.

appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ true);

3. Убедитесь в успешности верификации токена

Вот ваш текущий код верификации:

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

Необходимо уточнить, что getAppCheck() возвращает. Возможно, правильным будет заменять его на admin.appCheck().verifyToken(appCheckToken):

const appCheckClaims = await admin.appCheck().verifyToken(appCheckToken);

Если токен не может быть проверен, поймите, в чем именно заключается ошибка, выбрасываемая сервером.

Использование диагностических логов

Добавьте более детализированные логи в свой код для диагностики:

  • Логируйте входящие заголовки и сам токен.
  • В случае ошибки верификации, логируйте ошибку, чтобы понять природу проблемы.
try {
    const appCheckClaims = await admin.appCheck().verifyToken(appCheckToken);
} catch (err) {
    console.error("Ошибка верификации App Check:", err);
    res.status(401).send("Unauthorized");
}

Заключение

Проблемы с верификацией токена Firebase App Check могут быть вызваны неправильной конфигурацией ключа reCAPTCHA Enterprise или ошибками в коде верификации. Следуйте рекомендациям и внимательно проверяйте каждую стадию процесса, чтобы устранить проблему. Если все еще возникают трудности, рекомендуется обратиться к официальной документации Firebase или в службу поддержки для получения более индивидуальной помощи.

Оцените материал
Добавить комментарий

Капча загружается...