4

根据文档,我们可以添加 appcheck 如下,

exports.yourCallableFunction = functions.https.onCall((data, context) => {
  // context.app will be undefined if the request doesn't include a valid
  // App Check token.
  if (context.app == undefined) {
    throw new functions.https.HttpsError(
        'failed-precondition',
        'The function must be called from an App Check verified app.')
  }
});

我现在的问题是如何为以下场景添加应用程序检查?

exports.date = functions.https.onRequest((req, res) => {

});
4

4 回答 4

1

在客户端中,从 Firebase 获取 appCheck 令牌。将其发送到您的函数的标题中。从 req 对象的标头中获取令牌。使用 firebase-admin 验证令牌。我将在下面包含客户端的文档,然后是我如何使用 Apollo-client graphql 在客户端实现它的要点。然后我将包含后端的文档,然后是我如何实现后端的要点,再次使用 Apollo。

客户(来自文档):

const { initializeAppCheck, getToken } = require('firebase/app-check');

const appCheck = initializeAppCheck(
    app,
    { provider: provider } // ReCaptchaV3Provider or CustomProvider
);

const callApiWithAppCheckExample = async () => {
  let appCheckTokenResponse;
  try {
      appCheckTokenResponse = await getToken(appCheck, /* forceRefresh= */ false);
  } catch (err) {
      // Handle any errors if the token was not retrieved.
      return;
  }

  // Include the App Check token with requests to your server.
  const apiResponse = await fetch('https://yourbackend.example.com/yourApiEndpoint', {
      headers: {
          'X-Firebase-AppCheck': appCheckTokenResponse.token,
      }
  });

  // Handle response from your backend.
}; 

客户(我的实施要点)

import { setContext } from "@apollo/client/link/context";
import { app } from '../firebase/setup';
import { initializeAppCheck, ReCaptchaV3Provider, getToken } from "firebase/app-check"

let appCheck
let appCheckTokenResponse

const getAppCheckToken = async () => {
  const appCheckTokenResponsePromise = await getToken(appCheck, /* forceRefresh= */ false)
  appCheckTokenResponse = appCheckTokenResponsePromise
}

const authLink = setContext(async (_, { headers }) => {
  if (typeof window !== "undefined" && process.env.NEXT_PUBLIC_ENV === 'production') {
    appCheck = initializeAppCheck(app, {
      provider: new ReCaptchaV3Provider('my_public_key_from_recaptcha_V3'),
      isTokenAutoRefreshEnabled: true
    })
    await getAppCheckToken()
  }

  return {
    headers: {
      ...headers,
      'X-Firebase-AppCheck': appCheckTokenResponse?.token,
    },
  }
})

后端/服务器(来自文档)

const express = require('express');
const app = express();

const firebaseAdmin = require('firebase-admin');
const firebaseApp = firebaseAdmin.initializeApp();

const appCheckVerification = async (req, res, next) => {
    const appCheckToken = req.header('X-Firebase-AppCheck');

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

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

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

app.get('/yourApiEndpoint', [appCheckVerification], (req, res) => {
    // Handle request.
});

后端/服务器(我的实现要点)

import { https } from 'firebase-functions'
import gqlServer from './graphql/server'
const functions = require('firebase-functions')

const env = process.env.ENV || functions.config().config.env

const server = gqlServer()

const api = https.onRequest((req, res) => {
    server(req, res)
})

export { api }

. . .


import * as admin from 'firebase-admin';
const functions = require('firebase-functions');

const env = process.env.ENV || functions.config().config.env

admin.initializeApp()


appCheckVerification = async (req: any, res: any) => {
  const appCheckToken = req.header('X-Firebase-AppCheck')
  if (!appCheckToken) {
    return false
  }

  try {
    const appCheckClaims = await admin.appCheck().verifyToken(appCheckToken);
    return true
  } catch (error) {
    console.error(error)
    return false
  }
 }

. . .


const apolloServer = new ApolloServer({
  introspection: isDevelopment,
  typeDefs: schema,
  resolvers,
  context: async ({ req, res }) => {
            
    if (!isDevelopment && !isTest) {
      const appCheckVerification = await appCheckVerification(req, res)
        if (!appCheckVerification) throw Error('Something went wrong with verification')
 }
return { req, res, }
}
于 2021-09-06T20:59:33.860 回答
0

您可以在客户端生成应用检查令牌,并使用 firebase admin SDK 在服务器中验证令牌。是相同的firebase文档

于 2021-08-11T06:46:48.653 回答
0

Firebase 启用应用检查强制文档告诉您,要从您的函数验证调用者,您只需要检查 context.app 然后为您提供这样的示例

exports.EXAMPLE = functions.https.onCall((data, context) => {});

https://firebase.google.com/docs/app-check/cloud-functions?authuser=0

但是当你在谷歌云仪表板中部署你的函数时,你选择 HTTP FUNCTION -> nodejs 14 -> 然后你被定向到这样的代码

/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
exports.helloWorld = (req, res) => {
  let message = req.query.message || req.body.message || 'Hello World!';
  res.status(200).send(message);
};

当我看到这个时我的问题是:“如果我只有请求/响应,我将如何获得上下文”

答案很简单。你必须切换构造函数

您必须以某种方式重新编写函数,而不是像处理上下文/数据的任何快速函数那样处理 req/res

http 函数与可调用函数(处理上下文/数据的函数)不同

它是相似的,但并不完全相同,因此需要进行一些修改。

主要是如果您的函数处理异步内容并且响应延迟,您将需要重写许多内容

检查本教程 https://firebase.google.com/docs/functions/callable

于 2021-10-16T15:29:06.260 回答
0

如果您在 Cloud Functions 中强制执行应用程序检查,它将仅允许来自在您的项目中注册的应用程序的调用。

不过,我不确定这是否足以满足您的用例,因为我怀疑大多数可以提供 Web 挂钩的应用程序都已经实现了应用程序证明——这就是 App Check 识别有效请求的方式。

于 2021-06-22T14:39:30.123 回答