android - 注销后实时数据库onDisconnect未执行
问题描述
我已经实现了 Firebase 实时数据库存在系统,如官方 Firebase 文档中所示。我想让数据库安全,以便登录用户只能写入他们自己在数据库中的存在条目。因此,在登录时,用户写入参考路径/auth/{authId}/connections
,同时设置onDisconnect
删除值。
这是在 rtdb 中设置存在的 Android 应用程序的代码:
getFirebaseDatabase().goOnline();
DatabaseReference.goOnline();
// Since I can connect from multiple devices, we store each connection instance separately
// any time that connectionsRef's value is null (i.e. has no children) I am offline
final FirebaseDatabase database = getFirebaseDatabase();
final DatabaseReference myConnectionsRef = database.getReference("/auth/" + getFirebaseAuth().getUid() + "/connections");
// Stores the timestamp of my last disconnect (the last time I was seen online)
final DatabaseReference lastOnlineRef = database.getReference("/auth/" + getFirebaseAuth().getUid() + "/lastOnline");
connectedRef = database.getReference(".info/connected");
presenceChangeListener = connectedRef.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
boolean connected = snapshot.getValue(Boolean.class);
if (connected) {
DatabaseReference con = myConnectionsRef.push();
// When this device disconnects, remove it
con.onDisconnect().removeValue()
.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// Add this device to my connections list
// this value could contain info about the device or a timestamp too
con.setValue("ANDROID");
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d(TAG, "### Failed to set onDisconnect ###");
e.printStackTrace();
}
});
// When I disconnect, update the last time I was seen online
lastOnlineRef.onDisconnect().setValue(ServerValue.TIMESTAMP);
}
}
@Override
public void onCancelled(DatabaseError error) {
Log.w(TAG, "Listener was cancelled at .info/connected");
}
});
我遇到的问题是,如果用户注销,onDisconnect
除非我首先手动断开与 rtdb 的连接,否则不会执行。我假设在实时数据库上运行的代码被拒绝,因为身份验证不再有效。
//If I don't go offline first the record in rtdb will not be removed.
DatabaseReference.goOffline();
AuthUI.getInstance().signOut(this)
.addOnCompleteListener(new OnCompleteListener<Void>() {
public void onComplete(@NonNull Task<Void> task) {
// user is now signed out
Log.d(TAG, "Logged out");
application.clearData();
DatabaseReference.goOffline(); //This doesn't cause a presence update here
finish();
}
});
以上是我正在使用的解决方法,首先告诉数据库goOffline
然后注销。如果用户曾经通过另一种方式注销(Web 应用程序正在查看是否有多个选项卡正在使用该应用程序并且一个已注销),则用户将留下未删除的连接。
如果我在注销之前不调用goOffline()
,即使我强制关闭应用程序,rtdb 中的连接也不会被删除。
我还验证了如果我将 rtdb 规则更改为".write": "true"
<-这不好,我可以让一切正常工作。这告诉我,onDisconnect
当用户注销身份验证时,运行时有一个权限被拒绝。
我希望我的实时规则是这样的。
{
"rules": {
"auth": {
"$uid": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid"
}
}
}
}
我希望在设置onDisconnect
时仍然能够使用用户的身份验证执行onDisconnect
。
解决方案
附加onDisconnect()
处理程序时,您将在 Firebase 服务器上注册延迟写入。附加处理程序时以及触发处理程序时都会检查是否允许写入。而且由于您的用户在触发写入时已注销,因此您的规则会拒绝它。没有配置选项可以更改此行为,因此您必须想出不同的方法。
推荐阅读
- python - 使用 Python 将带有附件的 XML 发送到 SOAP ws
- javascript - 多个 Ajax 调用监听器
- coq - 宇宙不一致的一个简单案例
- google-cloud-platform - 连接到特定的 GCP 帐户
- variables - 如何使用 Pillow 将动画 GIF 保存到变量中
- python - 在树 ds 中按顺序遍历时递归函数失败
- sql - 在 SQL 中匹配对时收到额外的行
- android - RFCOMM_CreateConnection - 已打开状态:2,RFC 状态:4,MCB 状态:5 - isConnected 返回 false 并且无法重新连接
- angularjs - AngularJs 和 Bootstrap3:表单验证和必填字段
- javascript - 如何将数据发布和解析到节点快递