如何保护firebase云功能HTTP端点以仅允许firebase身份验证的用户?

如何保护firebase云功能HTTP端点以仅允许firebase身份验证的用户?,firebase,firebase-realtime-database,firebase-authentication,firebase-security,google-cloud-functions,Firebase,Firebase Realtime Database,Firebase Authentication,Firebase Security,Google Cloud Functions,使用新的firebase云函数,我决定将一些HTTP端点移动到firebase。 一切都很好。。。但我有以下问题。我有两个通过HTTP触发器构建的端点(云函数) 用于创建用户并返回自定义令牌的API端点 由Firebase管理SDK生成 获取特定用户详细信息的API端点 虽然第一个端点很好,但对于我的第二个端点,我只想为经过身份验证的用户保护它。意思是某人拥有我之前生成的令牌 我该如何着手解决这个问题 我知道我们可以使用 request.get('x-myheader') 但是,有没有一种方法

使用新的firebase云函数,我决定将一些HTTP端点移动到firebase。 一切都很好。。。但我有以下问题。我有两个通过HTTP触发器构建的端点(云函数)

  • 用于创建用户并返回自定义令牌的API端点 由Firebase管理SDK生成
  • 获取特定用户详细信息的API端点
  • 虽然第一个端点很好,但对于我的第二个端点,我只想为经过身份验证的用户保护它。意思是某人拥有我之前生成的令牌

    我该如何着手解决这个问题

    我知道我们可以使用

    request.get('x-myheader')
    
    但是,有没有一种方法可以像保护实时数据库一样保护端点

    你要做的事有一位官员负责。它说明了如何设置HTTPS函数,以要求使用客户端在身份验证期间接收到的令牌的授权头。该函数使用firebase管理库验证令牌


    此外,如果你的应用程序能够使用Firebase客户端库,那么你可以使用“”使这个样板文件变得更简单。

    正如@Doug所提到的,你可以使用
    Firebase admin
    来验证令牌。我举了一个简单的例子:

    exports.auth=functions.https.onRequest((req,res)=>{
    cors(请求、回复等){
    const tokenId=req.get('Authorization').split('Bearer')[1];
    返回admin.auth().verifyIdToken(tokenId)
    .然后((已解码)=>res.status(200).发送(已解码))
    .catch((err)=>res.status(401).send(err));
    });
    });
    
    在上面的示例中,我还启用了CORS,但这是可选的。首先,获取
    授权
    标题并找到
    令牌


    然后,您可以使用
    firebase admin
    验证该令牌。您将在响应中获得该用户的解码信息。否则,如果令牌无效,它将抛出一个错误。

    正如@Doug所提到的, 您可以使用,以便从客户端和服务器中删除

    可调用函数示例:

    export const getData=functions.https.onCall((数据,上下文)=>{
    //验证Firebase身份验证ID令牌
    如果(!context.auth){
    返回{message:'Authentication Required!',代码:401};
    }
    //做事。。
    const uid=context.auth.uid;
    const query=data.query;
    返回{message:'Some Data',代码:400};
    });
    
    可以直接从客户端调用它,如下所示:

    firebase.functions().httpscalable('getData')({query})。然后(result=>console.log(result));
    
    上述方法使用函数内部的逻辑对用户进行身份验证,因此仍必须调用函数进行检查

    这是一个非常好的方法,但为了全面性,有一种替代方法:

    您可以将函数设置为“private”,以便只有注册用户才能调用它(由您决定权限)。在这种情况下,未经身份验证的请求在函数的上下文之外被拒绝,并且根本不调用函数

    这里是对(a)和(b)的引用


    请注意,上面的文档是针对谷歌云平台的,事实上,这是有效的,因为每个Firebase项目也是一个GCP项目。与此方法相关的一个警告是,在撰写本文时,它仅适用于基于Google帐户的身份验证

    使用Express有一个很好的官方示例-将来可能会很方便:(粘贴在下面)

    请记住,
    exports.app
    使您的函数在
    /app
    slug下可用(在这种情况下,只有一个函数在
    /app/hello
    下可用)。要摆脱它,您实际上需要稍微重写Express part(用于验证的中间件部分保持不变-它工作得非常好,并且由于注释而非常容易理解)


    我一直在努力在golang GCP函数中获得正确的firebase身份验证。实际上没有这样的示例,因此我决定构建这个小型库:

    现在,您可以使用firebase auth轻松地对用户进行身份验证(这与gcp身份验证函数不同,并且身份感知代理不直接支持)

    以下是使用该实用程序的示例:

    导入(
    firebaseGcpAuth“github.com/Jblew/go firebase auth in gcp函数”
    auth“firebase.google.com/go/auth”
    )
    func SomeGCPHttpCloudFunction(w http.ResponseWriter,req*http.Request)错误{
    //您需要提供1.Context、2.request、3.firebase身份验证客户端
    var客户端*auth.client
    firebaseUser,err:=firebaseGcpAuth.AuthenticateFirebaseUser(context.Background(),req,authClient)
    如果错误!=零{
    如果未经过身份验证或承载令牌无效,则返回err//Error
    }
    //返回值:*auth.UserRecord
    }
    
    请记住,使用
    --允许未经身份验证的
    标志部署函数(因为firebase身份验证发生在函数执行内部)


    希望这能像帮助我一样帮助你。出于性能原因,我决定将golang用于云功能-Firebase中的Jędrzej

    ,为了简化代码和工作,这只是架构设计的问题

  • 对于公共可访问的站点/内容,请使用。若要仅限制同一站点或仅限制特定站点,请使用
    CORS
    来控制这方面的安全性。这是有意义的,因为
    Express
    由于其服务器端呈现内容,对SEO非常有用
  • 对于需要用户身份验证的应用程序,使用,然后使用
    上下文
    参数来省去所有麻烦。这也是有意义的,因为例如使用AngularJS构建的单页应用程序——AngularJS不利于SEO,但由于它是一个受密码保护的应用程序,因此您不需要修改
    /**
     * Copyright 2016 Google Inc. All Rights Reserved.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    'use strict';
    
    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    admin.initializeApp();
    const express = require('express');
    const cookieParser = require('cookie-parser')();
    const cors = require('cors')({origin: true});
    const app = express();
    
    // Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
    // The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
    // `Authorization: Bearer <Firebase ID Token>`.
    // when decoded successfully, the ID Token content will be added as `req.user`.
    const validateFirebaseIdToken = async (req, res, next) => {
      console.log('Check if request is authorized with Firebase ID token');
    
      if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
          !(req.cookies && req.cookies.__session)) {
        console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
            'Make sure you authorize your request by providing the following HTTP header:',
            'Authorization: Bearer <Firebase ID Token>',
            'or by passing a "__session" cookie.');
        res.status(403).send('Unauthorized');
        return;
      }
    
      let idToken;
      if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
        console.log('Found "Authorization" header');
        // Read the ID Token from the Authorization header.
        idToken = req.headers.authorization.split('Bearer ')[1];
      } else if(req.cookies) {
        console.log('Found "__session" cookie');
        // Read the ID Token from cookie.
        idToken = req.cookies.__session;
      } else {
        // No cookie
        res.status(403).send('Unauthorized');
        return;
      }
    
      try {
        const decodedIdToken = await admin.auth().verifyIdToken(idToken);
        console.log('ID Token correctly decoded', decodedIdToken);
        req.user = decodedIdToken;
        next();
        return;
      } catch (error) {
        console.error('Error while verifying Firebase ID token:', error);
        res.status(403).send('Unauthorized');
        return;
      }
    };
    
    app.use(cors);
    app.use(cookieParser);
    app.use(validateFirebaseIdToken);
    app.get('/hello', (req, res) => {
      res.send(`Hello ${req.user.name}`);
    });
    
    // This HTTPS endpoint can only be accessed by your Firebase Users.
    // Requests need to be authorized by providing an `Authorization` HTTP header
    // with value `Bearer <Firebase ID Token>`.
    exports.app = functions.https.onRequest(app);
    
    const hello = functions.https.onRequest((request, response) => {
      res.send(`Hello ${req.user.name}`);
    })
    
    module.exports = {
      hello
    }