Firebase Firestore代币不';设置自定义声明后,无法更新安全规则

Firebase Firestore代币不';设置自定义声明后,无法更新安全规则,firebase,google-cloud-firestore,firebase-security,Firebase,Google Cloud Firestore,Firebase Security,TLDR 基于自定义声明设置firestore安全规则 云firestore用户由电话验证创建 云函数在创建用户时触发,并添加一个自定义声明角色-admin。实时数据库中会更新一个条目,以指示索赔更新 监听客户端中实时数据库的更新,并调用user.getIdToken(true)更新自定义索赔后 能够在代码中看到添加的自定义声明 由于缺少权限(自定义声明),无法读取firestore中的文档 刷新浏览器页面,现在可以读取文档 我有一个云函数,可以在用户创建时添加自定义声明role-admin

TLDR

  • 基于自定义声明设置firestore安全规则
  • 云firestore用户由电话验证创建
  • 云函数在创建用户时触发,并添加一个自定义声明角色-admin。实时数据库中会更新一个条目,以指示索赔更新
  • 监听客户端中实时数据库的更新,并调用
    user.getIdToken(true)更新自定义索赔后
  • 能够在代码中看到添加的自定义声明
  • 由于缺少权限(自定义声明),无法读取firestore中的文档
  • 刷新浏览器页面,现在可以读取文档

  • 我有一个云函数,可以在用户创建时添加自定义声明
    role-admin

    exports.processSignUp = functions.auth.user().onCreate((user) => {
        const customClaims = {
          role: 'admin',
        };
        // Set custom user claims on this newly created user.
        return admin.auth().setCustomUserClaims(user.uid, customClaims)
          .then(() => {
            // Update real-time database to notify client to force refresh.
            const metadataRef = admin.database().ref("metadata/" + user.uid);
            // Set the refresh time to the current UTC timestamp.
            // This will be captured on the client to force a token refresh.
            return metadataRef.set({refreshTime: new Date().getTime()});
          })
          .catch(error => {
            console.log(error);
          });
    });
    
    我监听实时数据库中的更改事件,以检测用户自定义声明的更新

    let callback = null;
    let metadataRef = null;
    firebase.auth().onAuthStateChanged(user => {
      // Remove previous listener.
      if (callback) {
        metadataRef.off('value', callback);
      }
      // On user login add new listener.
      if (user) {
        // Check if refresh is required.
        metadataRef = firebase.database().ref('metadata/' + user.uid + '/refreshTime');
        callback = (snapshot) => {
          // Force refresh to pick up the latest custom claims changes.
          // Note this is always triggered on first call. Further optimization could be
          // added to avoid the initial trigger when the token is issued and already contains
          // the latest claims.
          user.getIdToken(true);
        };
        // Subscribe new listener to changes on that node.
        metadataRef.on('value', callback);
      }
    });
    
    我在云firestore上有以下安全规则

    service cloud.firestore {
      match /databases/{database}/documents {
        match /{role}/{document=**} {
            allow read: if request.auth != null &&
                            request.auth.token.role == role;
        }
      }
    }
    
    创建用户后,my cloud函数触发并添加自定义声明
    role=admin

    作为
    user.getIdToken(true)的结果在我的客户端上刷新令牌,我可以看到设置的自定义声明

    当我试图获取用户应该能够阅读的文档时,我获得了被云firestore安全规则拒绝的权限

    刷新浏览器页面时,我可以读取路径中的文档

    我希望能够在不刷新浏览器的情况下访问firebase文档。这有可能吗


    有人能告诉我我的方法/期望有什么问题吗?

    传播令牌的时间可能比您想象的要长。我广泛使用自定义声明-我发现有效的方法是设置
    .onIdTokenChanged()
    来跟踪uid和令牌更新,然后显式调用
    .getIdTokenResult(true)
    来更新我的本地令牌。只有在两者都完成后,您才能对Firestore和/或RTDB进行customClaim安全调用。

    我将添加-Firestore最近有一些更新似乎直接解决了这一问题。我没有尝试过它们,因为这里的解决方案对我有效。很遗憾,在我的情况下,收听
    onIdTokenChanged()
    并调用
    。getIdTokenResult(true)
    不起作用。我在
    .getIdTokenResult(true)中看到声明,然后
    ,但当我尝试读取
    .getIdTokenResult(true)中的文档时,仍然会出现
    缺少或权限不足
    错误。然后