如何使用经过身份验证的 id 令牌和数据库规则保护 Firebase Cloud Function HTTP 端点? [英] How to protect firebase Cloud Function HTTP endpoint using authenticated id token and database rules?

本文介绍了如何使用经过身份验证的 id 令牌和数据库规则保护 Firebase Cloud Function HTTP 端点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

admin.auth().verifyIdToken(tokenId)
      .then((decoded) => res.status(200).send(decoded))

我了解 verifyIdToken() 可以验证来自 Firebase 身份验证客户端的用户 ID 令牌.但是,我们需要通过确保数据库查询受到为令牌中标识的用户的数据库定义的安全规则的限制来保护我们的云功能.鉴于默认情况下 admin SDK 具有无限制的访问权限,我如何将其访问权限限制为经过身份验证的用户?

I understand verifyIdToken() can verify a user id token from Firebase Authentication clients. However we need to protect our Cloud Function by making sure database queries are limited by the security rules defined for the database for the user identified in the token. Given that the admin SDK has unlimited access by default, how to I limit its access to just that of the authenticated user?

推荐答案

看看下面的HTTPS功能.它执行以下任务:

Take a look at the following HTTPS function. It performs the following tasks:

  1. 使用 Admin SDK 验证 Firebase 身份验证 ID 令牌.令牌来自查询字符串(但您应该使用更好的解决方案 传输令牌).
  2. 从解码的令牌中提取用户的 UID.
  3. 制作默认 Firebase init 配置对象的副本,然后添加一个名为 databaseAuthVariableOverride,使用 UID,限制调用者权限.
  4. 使用新选项初始化 App 对象(名为user")的新非默认实例.此应用对象现在可用于访问数据库同时遵守为该用户制定的安全规则.
  5. Admin SDK 与 userApp 一起用于对某个保护路径进行数据库查询.
  6. 如果查询成功,请记住发送给客户端的响应.
  7. 如果查询因安全问题而失败,请记住要发送给客户端的错误响应.
  8. 清理此 Admin SDK 实例.此代码采取了所有预防措施以确保在所有情况下都调用 userApp.delete().不要忘记这样做,否则随着更多用户访问此功能,您会泄漏内存.
  9. 实际发送响应.这将终止函数.
  1. Verifies a Firebase Authentication ID token using the Admin SDK. The token comes from the query string (but you should use a better solution to transmit the token).
  2. Pulls the user's UID out of the decoded token.
  3. Makes a copy of the default Firebase init configuration object, then adds a property called databaseAuthVariableOverride to it, using the UID, to limit the privileges of the caller.
  4. Initializes a new non-default instance of an App object (named "user") with the new options. This App object can now be used to access the database while observing security rules in place for that user.
  5. The Admin SDK is used along with userApp to make a database query to some protect path.
  6. If the query was successful, remember the response to send to the cleint.
  7. If the query failed due to security rues, remember an error response to send to the client.
  8. Clean up this instance of the Admin SDK. This code takes all precautions to make sure userApp.delete() is called in all circumstances. Don't forget to do this, or you will leak memory as more users access this function.
  9. Actually send the response. This terminates the function.

这是一个工作函数:

const admin = require("firebase-admin")
admin.initializeApp()

exports.authorizedFetch = functions.https.onRequest((req, res) => {
    let userApp
    let response
    let isError = false

    const token = req.query['token']

    admin.auth().verifyIdToken(token)
    .then(decoded => {
        // Initialize a new instance of App using the Admin SDK, with limited access by the UID
        const uid = decoded.uid
        const options = Object.assign({}, functions.config().firebase)
        options.databaseAuthVariableOverride = { uid }
        userApp = admin.initializeApp(options, 'user')
        // Query the database with the new userApp configuration
        return admin.database(userApp).ref("/some/protected/path").once('value')
    })
    .then(snapshot => {
        // Database fetch was successful, return the user data
        response = snapshot.val()
        return null
    })
    .catch(error => {
        // Database fetch failed due to security rules, return an error
        console.error('error', error)
        isError = true
        response = error
        return null
    })
    .then(() => {
        // This is important to clean up, returns a promise
        if (userApp) {
            return userApp.delete()
        }
        else {
            return null
        }
    })
    .then(() => {
        // send the final response
        if (isError) {
            res.status(500)
        }
        res.send(response)
    })
    .catch(error => {
        console.error('final error', error)
    })
})

再次注意 userApp.delete() 应该在所有情况下被调用,以避免泄漏 App 实例.如果您想根据用户为每个新应用程序指定一个唯一名称,这不是一个好主意,因为随着新用户不断访问此功能,您仍然可能会耗尽内存.每次调用时都要清理它以确保安全.

Again, note that userApp.delete() should be called in all circumstances to avoid leaking instances of App. If you had the idea to instead give each new App a unique name based on the user, that's not a good idea, because you can still run out of memory as new users keep accessing this function. Clean it up with each call to be safe.

还要注意 userApp.delete() 应该在发送响应之前调用,因为发送响应会终止函数,并且您不希望有清理工作因任何原因中断.

Also note that userApp.delete() should be called before the response is sent, because sending a response terminates the function, and you don't want to have the cleanup interrupted for any reason.

这篇关于如何使用经过身份验证的 id 令牌和数据库规则保护 Firebase Cloud Function HTTP 端点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆