Firebase任务管理应用数据隔离问题:用户间任务互相可见求助
解决Firebase任务管理应用中用户数据共享的问题
当前开发的Kotlin+Firebase任务管理应用存在数据隔离问题——不同账号用户能互相查看彼此的任务,所有任务都存储在同一数据节点下。需要实现每个用户的数据独立存储,仅能访问自己的任务。
注册代码
class RegisterPage : AppCompatActivity() { private lateinit var binding: ActivityRegisterPageBinding private lateinit var firebaseAuth: FirebaseAuth private lateinit var progressDialog: ProgressDialog override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityRegisterPageBinding.inflate(layoutInflater) setContentView(binding.root) firebaseAuth = FirebaseAuth.getInstance() progressDialog = ProgressDialog(this) progressDialog.setTitle("Please wait") progressDialog.setCanceledOnTouchOutside(false) binding.backButton.setOnClickListener{ onBackPressed() } binding.regButton.setOnClickListener{ validateData() } } private var name ="" private var surname = "" private var email = "" private var password = "" private var confirmPassword = "" private fun validateData() { name = binding.regName.text.toString().trim() surname = binding.regSurname.text.toString().trim() email = binding.regEmail.text.toString().trim() password = binding.regCreate.text.toString().trim() confirmPassword = binding.regConfirm.text.toString().trim() if (name.isNotEmpty() && surname.isNotEmpty() && email.isNotEmpty() && password.isNotEmpty() && confirmPassword.isNotEmpty()) { if(password == confirmPassword){ createAccount() }else{ Toast.makeText(this, "Passwords do not match", Toast.LENGTH_SHORT).show() } }else{ Toast.makeText(this, "Please provide missing details", Toast.LENGTH_SHORT).show() } } private fun createAccount(){ progressDialog.setMessage("Creating account...") progressDialog.show() // Adding user to firebase firebaseAuth.createUserWithEmailAndPassword(email, password).addOnSuccessListener() { updateUser() }.addOnFailureListener{e-> progressDialog.dismiss() Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show() } } private fun updateUser(){ progressDialog.setMessage("Saving...") val timestamp = System.currentTimeMillis() // get curr user id val uid = firebaseAuth.uid // setup data to add in db val hashMap: HashMap<String, Any?> = HashMap() hashMap["uid"] = uid hashMap["name"] = name hashMap["surname"] = surname hashMap["email"] = email hashMap["timestamp"] = timestamp hashMap["profilePicture"] = "" hashMap["userType"] = "user" //set data to db val ref = FirebaseDatabase.getInstance().getReference("Users") ref.child(uid!!).setValue(hashMap).addOnSuccessListener { //Info saved, open home screen progressDialog.dismiss() Toast.makeText(this, "Account successfully created!", Toast.LENGTH_SHORT).show() startActivity(Intent(this@RegisterPage, HomeScreen::class.java)) finish() }.addOnFailureListener{ e -> //failed adding data to db progressDialog.dismiss() Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show() } } }
登录代码
class LoginPage : AppCompatActivity() { private lateinit var binding: ActivityLoginPageBinding private lateinit var firebaseAuth: FirebaseAuth private lateinit var progressDialog: ProgressDialog override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityLoginPageBinding.inflate(layoutInflater) setContentView(binding.root) firebaseAuth = FirebaseAuth.getInstance() progressDialog = ProgressDialog(this) progressDialog.setTitle("Please wait") progressDialog.setCanceledOnTouchOutside(false) binding.noAcc.setOnClickListener{ startActivity(Intent(this, RegisterPage::class.java)) } binding.loginButton.setOnClickListener{ validateUserData() } binding.forgotPassword.setOnClickListener{ startActivity(Intent(this, ForgotPassword::class.java)) } } private var email = "" private var password = "" private fun validateUserData(){ // Input data email = binding.loginEmail.text.toString().trim() password = binding.loginPassword.text.toString().trim() // Validating data if(!Patterns.EMAIL_ADDRESS.matcher(email).matches()){ Toast.makeText(this, "Invalid email format", Toast.LENGTH_SHORT).show() }else if(password.isEmpty()){ Toast.makeText(this, "Please enter your password", Toast.LENGTH_SHORT).show() }else{ loginUser() } } // Login firebase auth private fun loginUser() { progressDialog.setMessage("Logging in...") progressDialog.show() firebaseAuth.signInWithEmailAndPassword(email, password) .addOnSuccessListener { // Successful login checkUser() }.addOnFailureListener { e -> // failed to login progressDialog.dismiss() Toast.makeText(this, "${e.message}", Toast.LENGTH_SHORT).show() } } private fun checkUser() { /* Check user type - Firebase Auth * user - move to user dashboard * admin - move to admin dashboard*/ progressDialog.setMessage("Checking account...") val firebaseUser = firebaseAuth.currentUser!! val ref = FirebaseDatabase.getInstance().getReference("Users") ref.child(firebaseUser.uid).addListenerForSingleValueEvent(object: ValueEventListener{ override fun onDataChange(snapshot: DataSnapshot) { progressDialog.dismiss() // Get user type - user/admin val userType = snapshot.child("userType").value if(userType == "user"){ startActivity(Intent(this@LoginPage, HomeScreen::class.java)) finish() }else if (userType == "admin"){ startActivity(Intent(this@LoginPage, HomeScreen::class.java)) finish() } } override fun onCancelled(error: DatabaseError) { } }) } }
解决方案
要实现用户数据完全隔离,需从数据库结构、业务代码、安全规则三个层面同步修改:
1. 调整数据库结构
将任务数据按用户UID分区存储,结构改为:
Tasks |--- {用户UID} |--- {任务ID} |--- title: "任务标题" |--- description: "任务描述" |--- timestamp: 123456789 |--- ...其他任务字段
每个用户的任务都存储在自己UID对应的节点下,从结构上实现数据隔离。
2. 修改任务创建逻辑
创建任务时,获取当前登录用户的UID,将任务写入该用户专属节点:
private fun createTask(taskTitle: String, taskDesc: String) { val currentUser = firebaseAuth.currentUser ?: return val uid = currentUser.uid // 生成唯一任务ID val taskId = FirebaseDatabase.getInstance().getReference("Tasks") .child(uid) .push() .key ?: return val taskMap = hashMapOf( "title" to taskTitle, "description" to taskDesc, "timestamp" to System.currentTimeMillis(), "taskId" to taskId ) FirebaseDatabase.getInstance().getReference("Tasks") .child(uid) .child(taskId) .setValue(taskMap) .addOnSuccessListener { Toast.makeText(this, "任务创建成功", Toast.LENGTH_SHORT).show() } .addOnFailureListener { e -> Toast.makeText(this, "创建失败: ${e.message}", Toast.LENGTH_SHORT).show() } }
3. 修改任务读取逻辑
仅读取当前用户UID节点下的任务数据:
private fun loadUserTasks() { val currentUser = firebaseAuth.currentUser ?: return val uid = currentUser.uid val tasksRef = FirebaseDatabase.getInstance().getReference("Tasks").child(uid) tasksRef.addValueEventListener(object : ValueEventListener { override fun onDataChange(snapshot: DataSnapshot) { val taskList = mutableListOf<Task>() // 需自定义Task数据类 for (taskSnapshot in snapshot.children) { val task = taskSnapshot.getValue(Task::class.java) task?.let { taskList.add(it) } } // 将taskList绑定到RecyclerView等UI组件展示 } override fun onCancelled(error: DatabaseError) { Toast.makeText(this@HomeScreen, "加载失败: ${error.message}", Toast.LENGTH_SHORT).show() } }) }
4. 配置Firebase数据库安全规则
通过安全规则强制用户只能访问自己UID下的数据,防止恶意越权:
{ "rules": { "Users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } }, "Tasks": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } } } }
该规则确保只有登录用户能读写自己的用户信息和任务数据,从权限层面彻底隔离用户数据。
内容的提问来源于stack exchange,提问作者Skha
相关产品推荐
相关产品推荐

