Firebase onCreate 向 auth.user 添加自定义声明

Posted

技术标签:

【中文标题】Firebase onCreate 向 auth.user 添加自定义声明【英文标题】:Firebase onCreate add custom claims to the auth.user 【发布时间】:2020-10-24 11:00:34 【问题描述】:

我正在尝试添加自定义声明,isRegistered 到 firebase。我的 Firestore 有另一个 user 集合来保存注册信息记录。现在我正在尝试保留 isRegistered 自定义声明,但似乎无法正常工作。

exports.addRegisteredRole = functions.database.ref('/user')
    .onCreate((snap, context) => 
      return // **I added this later, but the issue still remains.**
        admin.auth()
            .setCustomUserClaims(context.auth.uid, isRegistered: true)
            .then(() => 
                console.log('done', snap)
                return 
                    message: 'done',
                    data: snap
                
            )
            .catch(err => 
                console.log('something went wrong', err);
                return err
            )
    );

我正在检查此声明,

currentUser.getIdTokenResult()
        .then(res => 
            console.log(res.claims.isRegistered)
        )

(授权用户对象)。即使我重新登录它仍然未定义。我做错了什么吗,我对 firebase 很陌生。

【问题讨论】:

弗兰克是对的,你没有返回一个在异步工作完成后解决的承诺。从数据库触发器返回数据也没有任何意义。这些数据不会去任何地方或做任何事情。 是的,我解决了这个问题。但它给出了相同的结果。 不幸的是,“相同的结果”很难解决。究竟会发生什么?调用是否显示在函数日志输出中?你的console.log 语句出现了吗? 【参考方案1】:

问题在于您的 onCreate 触发器。您假设您在 context.auth 对象中获取了 uid,这是不正确的。

onCreate 触发器将在您的“用户”集合中添加新文档时自动触发。在这种情况下, context.aut.uid 是未定义的。您应该在函数日志中对此进行跟踪。

您可以通过多种方式实现您的目标

    如果用户记录文档以用户ID作为文档的名称,您可以执行以下操作
exports.addRegisteredRole =
  functions.firestore
    .document('test/docId')
    .onCreate((snap, context) => 
      admin.auth()
        .setCustomUserClaims(snap.id,  isRegistered: true )
        .then(() => 
          console.log('done', snap)
          return 
            message: 'done',
            data: snap
          
        )
        .catch(err => 
          console.log('something went wrong', err)
          return err
        )
    )
    如果您使用其他名称命名用户记录文档,或者让 firebase 为您决定名称,那么您必须将 uid 作为文档数据中的属性。然后你使用 docSnapshot.data().uid 而不是 docSnapshot.id 如下
exports.addRegisteredRole =
  functions.firestore
    .document('test/docId')
    .onCreate((snap, context) => 
      admin.auth()
        .setCustomUserClaims(snap.data().uid,  isRegistered: true )
        .then(() => 
          console.log('done', snap)
          return 
            message: 'done',
            data: snap
          
        )
        .catch(err => 
          console.log('something went wrong', err)
          return err
        )
    )

祝你好运

【讨论】:

【参考方案2】:

我怀疑您的 Cloud Function 在对 Auth 的调用完成之前就被终止了。原因是您没有从代码的顶层返回任何内容,这意味着 Cloud Functions 假定您的代码在最终的 运行后完成。但由于对 `` 的调用是异步的,因此该调用尚未完成,例如您的 console.log('done', snap) 还没有运行。

exports.addRegisteredRole = functions.database.ref('/user')
.onCreate((snap, context) => 
    return admin.auth()
        .setCustomUserClaims(context.auth.uid, isRegistered: true)
        .then(() => 
            console.log('done', snap)
            return 
                message: 'done',
                data: snap
            
        )
        .catch(err => 
            console.log('something went wrong', err);
            return err
        )
);

【讨论】:

我做了这个改变。但结果是一样的。问题仍然存在。但是当我通过functions.http.onCall 执行此操作时,它运行良好。我只是想通过触发 onCreate 使其更安全。【参考方案3】:

我认为您应该使用带有通配符的 functions.firestore.document 来触发您的“用户”文档:

exports.addRegisteredRole = functions.firestore.document('/user/userId')
.onCreate((snap, context) =>  ... );

【讨论】:

【参考方案4】:

问题很可能是您没有将新的自定义声明传播给客户端。见这里:https://firebase.google.com/docs/auth/admin/custom-claims#propagate_custom_claims_to_the_client

这个 github 问题也指出了这一点:https://github.com/firebase/firebase-tools-ui/issues/424

如果您注销并以用户身份重新登录,它应该可以工作。简单地刷新登录用户的页面不会刷新用户的 ID 令牌。

由于在 onCreate 触发器中设置自定义声明是一个常见用例,因此最好在专门针对 firestore 的文档 (https://firebase.google.com/docs/auth/admin/custom-claims) 中对此进行说明,因为给定的示例是针对实时数据库的。

【讨论】:

以上是关于Firebase onCreate 向 auth.user 添加自定义声明的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Firebase Auth 作为 OIDC 向 Amplify GraphQL 发出经过身份验证的请求?

Firebase Phone Auth 不会用我的代码向我发送短信

Firebase Auth用户角色[重复]

身份验证错误后的 Firebase 用户数据

Firebase Auth我的变量安全/安全吗?

如何使用 Firebase Auth 将令牌发送回 android