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 ID 令牌的“aud”声明不正确
Firebase Auth setCustomClaims()不起作用