Входящий объект JSON не содержит поле client_email

Я пытаюсь создать облачную функцию Firebase. Так что я бы запустил локальную облачную функцию Firebase. Но это не работает, как настроить аутентификацию.

Я установил инструменты firebase: https://firebase.google.com/docs/functions/local-emulator. Я запустил команду firebase login, так что теперь я вошел в систему. Затем я создал свой ключ json с помощью этого учебника: https://cloud.google.com/docs/authentication/getting-started Теперь, если я echo $GOOGLE_APPLICATION_CREDENTIALS результат будет /home/$USER/.google/****.json которые содержат

"project_id","private_key_id","private_key","client_email", "client_id",  "auth_uri", "token_uri", "auth_provider_x509_cert_url", "client_x509_cert_url"

Также я попытался установить полную gcloud auth application-default login Google Cloud SDK и gcloud auth application-default login: gcloud auth application-default login но безуспешно.

Версии пакета Npm:

"firebase-functions":"3.0.2"
"firebase-admin": "8.2.0"

Я думаю, что предоставил достаточно информации, но не стесняйтесь спрашивать меня больше, если хотите.

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const app = express();
app.get("/", async (req, res) => {
admin.firestore().collection('something').get().then((collection) =>
    return res.send({"count": collection.docs.length, "status": 200});
});
exports.exports = functions.https.onRequest(app);

код не важен, самое главное, что даже когда я выполнил все эти шаги, когда я локально эмулирую свою базу Firebase с firebase serve и запускаю функцию, у меня появляется эта ошибка: Ошибка: входящий объект JSON не содержит поле client_email

Я могу убедиться, что файл json содержит поле client_email.

Можете ли вы помочь мне пройти аутентификацию в Google?

Спасибо за вашу помощь.

Ответы

Ответ 1

У меня была похожая проблема. Вероятно, это ошибка в версии 7.0.2 firebase-tools. Я откатился до версии 7.0.0 и теперь она работает.

Итак, временное решение:

npm i [email protected] -g  

Ответ 2

Короче:

admin.initializeApp({ credential: admin.credential.applicationDefault() });

Смотрите документы для admin.credential.applicationDefault()

Обновление: обратите внимание, что это рекомендуется только для тестирования/эксперимента:

Эта стратегия полезна при тестировании и экспериментах, но может затруднить определение учетных данных, используемых вашим приложением. Мы рекомендуем явно указать, какие учетные данные следует использовать приложению,... Source

Немного больше информации

У меня было то же самое при попытке вызвать локально функцию firebase, которая пытается обновить некоторые документы в базе данных firestore в пакетном режиме. (Не тестировал без партии).

Чтобы начать локально вызывать функции firebase, я использую:

firebase function:shell

Как вы, вероятно, знаете, здесь перечислены доступные функции для вашего проекта.

Я вызвал свою функцию и получил следующую ошибку callstack:

Unhandled error Error: The incoming JSON object does not contain a client_email field
>      at JWT.fromJSON (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-auth-library\build\src\auth\jwtclient.js:165:19)
>      at GoogleAuth.fromJSON (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-auth-library\build\src\auth\googleauth.js:294:16)
>      at GoogleAuth.getClient (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-auth-library\build\src\auth\googleauth.js:476:52)
>      at GrpcClient._getCredentials (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-gax\build\src\grpc.js:107:40)
>      at GrpcClient.createStub (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-gax\build\src\grpc.js:223:34)
>      at new FirestoreClient (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\v1\firestore_client.js:128:39)
>      at ClientPool.Firestore._clientPool.pool_1.ClientPool [as clientFactory] (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\index.js:315:26)
>      at ClientPool.acquire (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\pool.js:61:35)
>      at ClientPool.run (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\pool.js:114:29)
>      at Firestore.readStream (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\index.js:995:26)

RESPONSE RECEIVED FROM FUNCTION: 500, {
  "error": {
    "status": "INTERNAL",
    "message": "INTERNAL"
  }
}

Я выполнял свою функцию локально, используя командную строку: firebase functions:shell

Я использовал этот код:

// Reference report in Firestore
const db = admin.firestore();

admin.initializeApp();

export const performMyCallableFirebaseFunction = (db, { from, to }) => {
    return db.collection("collectionName").where("prop", "==", from).limit(500).get().then(snapshot => {
        if (snapshot.empty) return new Promise(resolve => resolve('No docs found with prop: ${from}'));

        const batch = db.batch();
        snapshot.forEach(doc => batch.update(doc.ref, { prop: to }));

        return batch.commit();
    });
};
exports.myCallableFirebaseFunction = functions.https.onCall(data => performMyCallableFirebaseFunction(db, data.from, data.to));

Я изменил линию

admin.initializeApp();

в

admin.initializeApp({ credential: admin.credential.applicationDefault() });

и теперь я смог вызвать свою функцию локально, используя:

firebase functions:shell
firebase > myCallableFirebaseFunction({from: "foo", to: "bar"})

Смотрите документы для admin.credential.applicationDefault()

Ответ 3

Вероятно, вам нужно настроить Firebase Admin SDK для использования эмулятора Firebase. Это можно сделать, передав свойство credential при вызове admin.initializeApp():

const serviceAccount = require('../serviceAccount.json');

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

Вы можете скачать JSON файл своей учетной записи службы в консоли Firebase:

  • Нажмите на значок "Настройки";
  • Перейдите в раздел "Пользователи и разрешения";
  • Нажмите на ссылку, где написано, что "N сервисных учетных записей также имеют доступ к этому проекту";
  • Нажмите на кнопку "Создать новый закрытый ключ".

Ответ 4

Создав проект Firebase, вы можете инициализировать SDK с помощью стратегии авторизации, которая объединяет файл учетной записи службы и учетные данные приложения Google по умолчанию.

Чтобы аутентифицировать учетную запись службы и разрешить ей доступ к службам Firebase, необходимо сгенерировать файл закрытого ключа в формате JSON.

Чтобы создать файл личного ключа для вашей учетной записи службы:

  1. В консоли Firebase откройте "Настройки"> "Учетные записи служб".

  2. Нажмите "Создать новый закрытый ключ", затем подтвердите, нажав "Создать ключ".

  3. Надежно храните файл JSON, содержащий ключ.

Задайте для переменной среды GOOGLE_APPLICATION_CREDENTIALS путь к файлу JSON, в котором содержится ключ учетной записи службы. Эта переменная применяется только к текущему сеансу оболочки, поэтому, если вы открываете новый сеанс, установите переменную снова.

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

https://firebase.google.com/docs/admin/setup?authuser=3

Ответ 5

Я получал эту ошибку при запуске firebase emulators:start.

Согласно исследованию этой ошибки: https://github.com/firebase/firebase-tools/issues/1451, кажется, что это проблема с обращением к приложению напрямую, а не через модуль администратора.

то есть это вызывает ошибку:

const app = admin.initializeApp();
const firestore = app.firestore();

но это не

admin.initializeApp();
const firestore = admin.firestore();

Однако для первоначального вопроса вы используете admin.firestore(), чтобы не было проблем. Кажется, что admin.initializeApp() никогда не вызывается. Возможно, это может быть причиной вашей проблемы?

Ответ 6

Вот как я решил проблему после нескольких часов борьбы:

Короткий ответ:

Создать ключ Firebase-adminsdk

Как это сделать:

  • Перейдите в Google-console > Service accounts https://console.cloud.google.com/projectselector2/iam-admin

  • Выберите свой проект

  • Выберите ваш firebase-admin-sdk похож на [email protected]
  • Включить режим редактирования
  • Create key и выбрать JSON
  • Вы получаете возможность скачать .json. Который имеет ProjectID, PrivateKey and ClientEmail в нем
  • используйте информацию, подобную этой, где вы инициализируете свое приложение:
// Providing a service account object inline
admin.initializeApp({
    credential: admin.credential.cert({
        projectId: "<PROJECT_ID>",
        clientEmail: "[email protected]<PROJECT_ID>.iam.gserviceaccount.com",
        privateKey: "-----BEGIN PRIVATE KEY-----<KEY>-----END PRIVATE KEY-----\n"
    })
});