【问题标题】:query permissions for custom token自定义令牌的查询权限
【发布时间】:2019-02-11 14:08:26
【问题描述】:

我有一个自定义令牌,其中包含 appid 有效负载,用于识别第三方应用。

我想验证对我的数据的读取/写入,以便:

  1. 用户已登录(有一个有效的uid/令牌)
  2. appid 已在 /apps 集合中注册
  3. uidappid 是记录中的字段并与凭据匹配
  4. (与此问题无关,但要完整)此记录与文档的架构匹配。

当前最佳解决方案和剩余问题

我最终偶然发现的这个答案相当不错,但可能会有所改进。

我要做的第一件事是正确识别我在自定义令牌中提供的有效负载——因为我使用云服务功能来生成有效负载 (graphcool),我的有效负载是 default: { appid } 而不仅仅是 @ 987654323@。从那里开始,只需对权限进行一些改写就足以使用我想象的当前规则成功验证:

service cloud.firestore {
  match /databases/{database}/documents {

    match /sampleData/{type}/{appName}/{record} {
      allow read: if isSignedIn() && isValidApp(database) && ownsExisting() && appIdInExisting()
      allow write: if isSignedIn() && isValidApp(database) && ownsPayload() && appIdInPayload()
    }

    // functions
    function isSignedIn () {
        return request.auth != null
    }

    function isValidApp (database) {
        return exists(/databases/$(database)/documents/apps/$(request.auth.token.appid))
    }

    function ownsExisting () {
        return resource.data.uid == request.auth.uid
    }

    function ownsPayload () {
        return request.resource.data.uid == request.auth.uid
    }

    function appIdInExisting () {
        return resource.data.app_id == request.auth.token.appid
    }

    function appIdInPayload () {
        return request.resource.data.app_id == request.auth.token.appid
    }
  }
}

虽然有人可以做得更好。

  1. 有什么方法可以在不使用存在请求的情况下验证 appid(并且不编写 if-else if 链)——就像使用数组一样也许直接在规则中?

  2. 如何确保负载中指定的 appid 与我在向客户端第三方应用程序颁发服务凭据时所设想的匹配?

    李>

编辑:原始问题

我想我自己至少可以得到前两个:

service cloud.firestore {
  match /databases/{database}/documents {

    match /sampleData {
      allow read: if isSignedIn() && isValidApp() && ownsExisting() && appIdInExisting()
      allow write: if isSignedIn() && isValidApp() && ownsPayload() && appIdInPayload()
    }

    // functions
    function isSignedIn () {
        return request.auth != null
    }

    function isValidApp () {
        return get(path('apps')).data.child(request.auth.token.appid).exists()
    }

    function ownsExisting () {
        return resource.data.uid == request.auth.uid
    }

    function ownsPayload () {
        return request.resource.data.uid == request.auth.uid
    }

    function appIdInExisting () {
        return resource.data.app_id == request.auth.token.appid
    }

    function appIdInPayload () {
        return request.resource.data.app_id == request.auth.token.appid
    }
  }
}

/apps 有 1 个名为“sample-app-id”的文档,其中 idname 字段为“sample-app-id”...但使用此在我的令牌中不起作用:FirebaseError: Missing or insufficient permissions

我正在通过我的服务器上的这个函数生成令牌:

var FirebaseAdmin = require('firebase-admin')
var serviceAccount = require('./firebase-service-credentials.json')
var claims = require('./custom-token-claims') // {appid: 'sample-app-id'}

let credential = FirebaseAdmin.credential.cert(serviceAccount)
FirebaseAdmin.initializeApp({ credential })

const generateTokenWithPayload = async id => {
  try {
    const token = await FirebaseAdmin.auth().createCustomToken(id, claims)

    return { data: { token } }
  } catch (err) {
    return { error }
  }
}

module.exports = async event =>
  await generateTokenWithPayload(event.data.userIdentifier)

在发布之前,我正在登录——我可以验证的这部分似乎正在工作,因为我在 firebase 控制台的 Authentication -> Users 选项卡中看到了新的非匿名用户:

— Feb 11, 2019 Feb 11, 2019 smaple-user-id

这基本上是客户端代码:

await firebase
      .auth()
      .signInWithCustomToken(token)
      .catch(console.error)
const db = await firebase.firestore()
db.collection(path + this.state.appName).add(payload) 

我将使用架构 {app_id, app_name, date, metric, uid} 的记录发布到 sampleData/metrics/sample-app-name/{auto-generated}

注释:

  • 将要注册的应用程序数量很少——从财务角度来看,如果可能的话,将其设置为权限文件中的静态数组可能是有意义的,而不是 get 请求。

  • 重大改进 - 我刚刚注意到 request.auth.token.appid 应该是 request.auth.token.default.appid 因为我使用的是 export default 而不是 modules.export

【问题讨论】:

    标签: firebase firebase-authentication google-cloud-firestore firebase-security


    【解决方案1】:

    这个答案相当不错,但可能会有所改进。

    我要做的第一件事是正确识别我在自定义令牌中提供的有效负载——因为我使用云服务功能来生成有效负载 (graphcool),我的有效负载是 default: { appid } 而不仅仅是 @ 987654322@。从那里开始,只需对权限进行一些改写就足以使用我想象的当前规则成功验证:

    service cloud.firestore {
      match /databases/{database}/documents {
    
        match /sampleData/{type}/{appName}/{record} {
          allow read: if isSignedIn() && isValidApp(database) && ownsExisting() && appIdInExisting()
          allow write: if isSignedIn() && isValidApp(database) && ownsPayload() && appIdInPayload()
        }
    
        // functions
        function isSignedIn () {
            return request.auth != null
        }
    
        function isValidApp (database) {
            return exists(/databases/$(database)/documents/apps/$(request.auth.token.appid))
        }
    
        function ownsExisting () {
            return resource.data.uid == request.auth.uid
        }
    
        function ownsPayload () {
            return request.resource.data.uid == request.auth.uid
        }
    
        function appIdInExisting () {
            return resource.data.app_id == request.auth.token.appid
        }
    
        function appIdInPayload () {
            return request.resource.data.app_id == request.auth.token.appid
        }
      }
    }
    

    虽然有人可以做得更好。

    1. 有什么方法可以在不使用存在请求的情况下验证 appid(并且不编写 if-else if 链)——就像使用数组一样也许直接在规则中?

    2. 如何确保负载中指定的 appid 与我在向客户端第三方应用程序颁发服务凭据时所设想的匹配?

      李>

    【讨论】:

      猜你喜欢
      • 2019-12-19
      • 2018-02-19
      • 1970-01-01
      • 2016-01-10
      • 1970-01-01
      • 2021-10-05
      • 2021-08-11
      • 1970-01-01
      • 2018-04-19
      相关资源
      最近更新 更多