如何保护firebase云功能HTTP端点以仅允许firebase身份验证的用户?
使用新的firebase云函数,我决定将一些HTTP端点移动到firebase。 一切都很好。。。但我有以下问题。我有两个通过HTTP触发器构建的端点(云函数)如何保护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') 但是,有没有一种方法
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
}