Firebase Auth Custom 声明未传播到客户端

Posted

技术标签:

【中文标题】Firebase Auth Custom 声明未传播到客户端【英文标题】:Firebase Auth Custom claims not propagating to client 【发布时间】:2018-06-11 02:16:11 【问题描述】:

我有一个 UID 为 1 的用户,其中自定义声明设置为,

frompos=true

我正在通过 ADMIN SDK for java 为该用户设置新的自定义声明,方法如下:

Map<String,Object> claims = new HashMap<>();

claims.put("frompos",false);

FirebaseAuth.getInstance().setCustomUserClaimsAsync("1", claims).get(10000,
                        TimeUnit.MILLISECONDS);

我在服务器端打印声明以检查声明是否已设置:

UserRecord user = FirebaseAuth.getInstance().getUserAsync("1").get(10000,
                        TimeUnit.MILLISECONDS);

LOG.debug("user new claims " + user.getCustomClaims());

预期的结果是声明被设置:

user new claims frompos=false

现在在 android sdk 端,我的用户已经登录,所以我手动刷新 ID 令牌以传播文档所说的声明 (https://firebase.google.com/docs/auth/admin/custom-claims)

FirebaseAuth.getInstance().getCurrentUser().getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() 
         @Override
         public void onComplete(@NonNull Task<GetTokenResult> task) 
                    if(task.isSuccessful())
                    Log.d("FragmentCreate","Success refreshing token "+(FirebaseAuth.getInstance().getCurrentUser()==null));

                    Log.d("FragmentCreate","New token "+task.getResult().getToken());

                        
                    
         ).addOnFailureListener(new OnFailureListener() 
                    @Override
                    public void onFailure(@NonNull Exception e) 
                        Log.d("FragmentCreate","Failure refreshing token "+(FirebaseAuth.getInstance().getCurrentUser()==null)+" "+e.toString());
                    
         );

现在我使用此处打印的打印 ID 令牌并在服务器端对其进行验证并从中打印声明

 FirebaseToken tokenTest = FirebaseAuth.getInstance(ahmedabadRepoApp).verifyIdTokenAsync(token).get(10000,TimeUnit.MILLISECONDS);

 LOG.debug("Token claims are "+tokenTest.getClaims());

但此处打印的声明是:

"aud":"ahmedabadrepo","auth_time":1514724115,"email_verified":false,"exp":1514730425,"iat":1514726825,"iss":"https://securetoken.google.com/ahmedabadrepo","sub":"1","frompos":true,"user_id":"1","firebase":"identities":,"sign_in_provider":"custom"

因此,即使我手动刷新了 Id 令牌,frompos 值也不会传播到客户端 sdk。

【问题讨论】:

在管理员端设置声明后是否强制刷新令牌?在某些时候,您似乎成功设置了“frompos”,因为它出现在 ID 令牌中,但显示为不同的值。 我使用自定义令牌登录,并将 frompos 设置为 true。然后通过管理员更改并在那里打印。然后我强制刷新客户端。即使管理员 sdk 将其设置为 false,此处的值仍然保持为 true 你有这方面的更新吗? 不幸的是,我在他们的支持下提出了一张票,但他们无法复制它。不得不放弃这个想法,现在我在我的过程中使用了一种新方法。这对我来说似乎是一个明确的错误 【参考方案1】:

我在 Angular 中遇到了同样的问题 - 我使用服务器上的 Admin SDK 设置了声明,但它们不会出现在客户端的用户中。

使用以下内容,我可以看到负载中的声明:

  this.firebaseAuth.auth.currentUser.getIdToken().then(idToken => 

    const payload = JSON.parse(this.b64DecodeUnicode(idToken.split('.')[1]))

    console.log(payload);
    

  )

b64DecodeUnicode(str) 
    return decodeURIComponent(atob(str).replace(/(.)/g, function (m, p) 
        var code = p.charCodeAt(0).toString(16).toUpperCase();
        if (code.length < 2) 
            code = '0' + code;
        
        return '%' + code;
    ));
  

这是我复制上述内容的good write up:

目前客户端代码必须解析和解码用户 ID 令牌以提取嵌入其中的声明。在未来, Firebase 客户端 SDK 可能会为此用途提供更简单的 API 案例。

来自 Firebase Docs 的相关信息:

只能通过用户的 ID 令牌检索自定义声明。 可能需要访问这些声明以修改基于客户端的 UI 关于用户的角色或访问级别。但是,后端访问应该 验证后始终通过 ID 令牌强制执行,并且 解析其声明。自定义声明不应直接发送到 后端,因为它们不能在令牌之外被信任。

一旦最新的声明传播到用户的 ID 令牌,您就可以 通过首先检索 ID 令牌然后解析其来获取这些声明 有效载荷(base64 解码):

// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
firebase.auth().currentUser.getIdToken()
  .then((idToken) => 
     // Parse the ID token.
     const payload = JSON.parse(b64DecodeUnicode(idToken.split('.')[1]));
     // Confirm the user is an Admin.
     if (!!payload['admin']) 
       showAdminUI();
     
  )
  .catch((error) => 
    console.log(error);

【讨论】:

我确实做到了...问题是...新的 ID 令牌没有新的声明,它有修改前的旧声明。 我正在打印新的 id 令牌并在我的服务器端再次对其进行解码以检查...不知道如何在 android 中解码 b64 Unicode,因此通过发送新令牌再次进行到我的服务器解码。新令牌根本没有获得新的声明集 好的。抱歉,我帮不上忙。 没关系,这似乎是一个错误......我已经在 Firebase 支持下提出了这个问题,他们正在努力解决并告诉我【参考方案2】:

这可能会有所帮助:https://***.com/a/38284384/9797228

firebase.auth().currentUser.getIdToken(true)

【讨论】:

【参考方案3】:

客户端 sdk 正在缓存旧令牌(旧声明)。

您应该在更改声明后添加一种机制来刷新它(例如推送通知),或者只是等待旧令牌过期或用户退出并再次登录。

这里有解释https://youtu.be/3hj_r_N0qMs?t=719

编辑

您可以使用 firebase.auth().currentUser.getIdToken(true) 强制 sdk 刷新令牌

【讨论】:

以上是关于Firebase Auth Custom 声明未传播到客户端的主要内容,如果未能解决你的问题,请参考以下文章

Firebase Auth - 自定义声明的用户列表

Firebase Auth ID 令牌的“aud”声明不正确

Firebase Auth setCustomClaims()不起作用

如何在 Firebase 中创建基于角色的访问控制或自定义声明

Flutter Firebase Auth 密码重置

signInWithCustomToken()使用Firebase自己的令牌