Kus*_*han 5 android firebase firebase-authentication
我一直在使用FirebaseAuth登录用户,并且注意到FirebaseUser的getToken方法返回的ID令牌不同于FCM FirebaseInstanceIdService。
FirebaseAuth ID令牌和返回令牌上的FCM实例ID onTokenRefresh之间到底有什么区别?实例ID令牌和ID令牌的名称相似,因此对我来说有点混乱。
根据我的观察,通过getIdToken
FirebaseUser对象上的方法获得的FirebaseAuth令牌在一小时内到期。
getIdToken(boolean forceRefresh)
Run Code Online (Sandbox Code Playgroud)
例如令牌是...
01-18 17:20:08.904 15947-15947/? D/FragmentCreate: Token found without force refresh from a single thread eyJhbGciOiJSUzI1NiIsImtpZCI6ImExNTAxNjY5NTNiYTFhMjBjY2FhOTdmOTM4M2NiMDg3OTYyODBkZDcifQ.eyJpc3MiOiJodHR....JTXpA
Run Code Online (Sandbox Code Playgroud)
我观察到将forceRefresh设置为true会立即更改令牌。
例如。
01-18 17:22:16.990 15947-15947/? D/FragmentCreate: Token found single thread after force refresh eyJhbGciOiJSUzI1NiIsImtpZCI6ImExNTAxNjY5NTNiYTFhMjBjY2FhOTdmOTM4M2NiMDg3OTYyODBkZDcifQ.eyJpc3MiOiJod.......xQCA
Run Code Online (Sandbox Code Playgroud)
现在,当我在最后一次显示的强制刷新一个小时后调用getIdToken(false)时,令牌确实随着过期而发生了变化,并且从深入研究Firebase代码中发现了一些类似isValid()的检查,我猜测即使强制刷新为false,令牌到期并刷新它。
为了使事情变得有趣,我getIdToken
在令牌到期后不久从两个线程同时调用了(false),以查看两者是否打印了不同的令牌,因为两者都将看到令牌已同时过期,因此双方都应尝试刷新令牌
例如。
01-18 18:25:29.479 29849-29849/com.foodiniq.waitlist.katana D/FragmentCreate: Token found from thread1 after expiry eyJhbGciOiJSUzI1NiIsImtpZCI6ImExNTAxNjY5NTNiYTFhMjBjY2FhOTdmOTM4M2NiMDg3OTYyODBkZDcifQ.eyJpc3MiOiJod........GpdbA
01-18 18:25:30.071 29849-29849/com.foodiniq.waitlist.katana D/FragmentCreate: Token found from thread1 after expiry eyJhbGciOiJSUzI1NiIsImtpZCI6ImExNTAxNjY5NTNiYTFhMjBjY2FhOTdmOTM4M2NiMDg3OTYyODBkZDcifQ.eyJpc3MiOiJod........GpdbA
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,该令牌确实确实如我所预料的那样得到了刷新,但是它们两个都给出了相同的结果。这种暗示表明,用于内部获取令牌的方法可能已同步,并且至少在从两个不同的线程将强制刷新设置为false的情况下调用该方法至少会返回相同的结果。如果将forceRefresh设置为true,则同时线程打印具有相同值的新令牌时也会显示相似的结果
我是否假设getIdToken(false)方法是线程安全的,并且在同时调用时在所有线程中始终仅返回相同的值,这是正确的吗?这种行为会与getIdToken(true)不同吗?
PS用于获取令牌而无需从两个线程刷新的代码是
Thread testThread1 = new Thread(new Runnable() {
@Override
public void run() {
if(FirebaseAuth.getInstance().getCurrentUser()!=null){
FirebaseAuth.getInstance().getCurrentUser().getIdToken(false).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
@Override
public void onComplete(@NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
Log.d("FragmentCreate","Token found from thread1 after expiry "+task.getResult().getToken());
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d("FragmentCreate","Token failed from main thread single "+e.toString());
}
});
}
}
});
Thread testThread2 = new Thread(new Runnable() {
@Override
public void run() {
if(FirebaseAuth.getInstance().getCurrentUser()!=null){
FirebaseAuth.getInstance().getCurrentUser().getIdToken(false).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
@Override
public void onComplete(@NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
Log.d("FragmentCreate","Token found from thread2 after expiry "+task.getResult().getToken());
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d("FragmentCreate","Token failed from main thread single "+e.toString());
}
});
}
}
});
testThread1.start();
testThread2.start();
Run Code Online (Sandbox Code Playgroud)
从一个线程强制刷新调用令牌的方法是:
if(FirebaseAuth.getInstance().getCurrentUser()!=null){
FirebaseAuth.getInstance().getCurrentUser().getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
@Override
public void onComplete(@NonNull Task<GetTokenResult> task) {
if (task.isSuccessful()) {
Log.d("FragmentCreate","Token found single thread after force refresh "+task.getResult().getToken());
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d("FragmentCreate","Token failed from main thread single "+e.toString());
}
});
}
Run Code Online (Sandbox Code Playgroud)
由于以下原因,我想要线程安全的实现:
在每次启动应用程序时,我都会获取令牌而不会强制刷新。并在所有后续请求中使用此令牌。(因此,该令牌可能已经过期,但是用户保持应用程序运行一个小时的情况不太可能)
我在后端所做的就是您所说的验证ID令牌。在这里,令牌可能已经过期。因此,我正在发送一个响应代码,该代码告诉客户端手动刷新令牌。现在,这是在后端的所有Servlet上完成的,因此许多Servlet可以同时返回过期的响应代码。关于此响应,我将从任何获得响应代码的线程上刷新客户端上的令牌,从而导致多个不同的线程在客户端上调用刷新方法。我基本上担心,这可能是令牌更新中的配额
Firebase ID 令牌和 FCM 令牌是两个完全不同的东西:第一个是身份验证令牌,用于验证后端服务器上的请求,后者用于唯一标识应用程序安装的实例,以了解向谁发送正确的消息. 还要考虑 Firebase 用户身份验证 ID - 它是特定用户帐户的线程安全和唯一 ID。
来自官方文档
验证 ID 令牌
如果您的 Firebase 客户端应用程序与自定义后端服务器通信,您可能需要识别该服务器上当前登录的用户。要安全地执行此操作,请在成功登录后使用 HTTPS 将用户的 ID 令牌发送到您的服务器。然后,在服务器上,验证 ID 令牌的完整性和真实性并从中检索 uid。您可以使用以这种方式传输的 uid 来安全地识别您服务器上当前登录的用户。
而(来自官方文档):
访问设备注册令牌
在您的应用程序初始启动时,FCM SDK 会为客户端应用程序实例生成一个注册令牌。如果您想定位单个设备或创建设备组,则需要通过扩展 FirebaseInstanceIdService 来访问此令牌。本节介绍如何检索令牌以及如何监视对令牌的更改。由于初始启动后令牌可能会轮换,因此强烈建议您检索最新更新的注册令牌。
在以下情况下,注册令牌可能会更改:
- 应用程序删除实例 ID
- 该应用程序已在新设备上恢复
- 用户卸载/重新安装应用程序
- 用户清除应用数据。
因此,这一点似乎有点偏离重点:为什么要拥有一个线程安全且唯一的身份验证令牌?在您的后端服务器上,您可以uid
通过调用适当的函数(例如 Node.js 代码)来简单地获取用户信息:
admin.auth().verifyIdToken(idToken)
.then(function(decodedToken) {
var uid = decodedToken.uid;
// ...
}).catch(function(error) {
// Handle error
});
Run Code Online (Sandbox Code Playgroud)
如果这些信息改变了对代码中发生的事情的理解,请随时详细说明/改进问题。
归档时间: |
|
查看次数: |
2406 次 |
最近记录: |