如何在Firebase中向特定用户发送PDF并仅允许该用户查看?
实现向Firebase特定用户发送私有PDF及数据的方案
需求核心
- 上传的数据/PDF仅目标指定用户可见
- 需通过用户UID定向发送内容
- 确保数据安全,非目标用户无法访问
步骤1:界面调整
在activity_uploadfile.xml中添加输入框,用于填写目标用户的UID:
<EditText android:id="@+id/targetUserId" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="输入目标用户UID" android:inputType="text" />
步骤2:核心代码修改
修正原代码空指针问题,添加目标UID校验,调整数据存储路径以绑定目标用户:
import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.Manifest; import android.app.ProgressDialog; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.WindowManager; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; import com.google.android.gms.tasks.OnSuccessListener; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.auth.FirebaseUser; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.storage.FirebaseStorage; import com.google.firebase.storage.OnProgressListener; import com.google.firebase.storage.StorageReference; import com.google.firebase.storage.UploadTask; import com.karumi.dexter.Dexter; import com.karumi.dexter.PermissionToken; import com.karumi.dexter.listener.PermissionDeniedResponse; import com.karumi.dexter.listener.PermissionGrantedResponse; import com.karumi.dexter.listener.PermissionRequest; import com.karumi.dexter.listener.single.PermissionListener; public class uploadfile extends AppCompatActivity { ImageView imagebrowse, imageupload, filelogo, cancelfile; Uri filepath; EditText filetitle, targetUserId; // 新增目标UID输入框 StorageReference storageReference; DatabaseReference databaseReference; private FirebaseAuth firebaseAuth; String currentUid; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_uploadfile); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 先初始化FirebaseAuth,避免空指针 firebaseAuth = FirebaseAuth.getInstance(); FirebaseUser user = firebaseAuth.getCurrentUser(); if (user != null) { currentUid = user.getUid(); } else { Toast.makeText(this, "请先登录", Toast.LENGTH_SHORT).show(); finish(); return; } storageReference = FirebaseStorage.getInstance().getReference(); databaseReference = FirebaseDatabase.getInstance().getReference("user_files"); // 调整根节点名称,区分用户专属文件 filetitle = findViewById(R.id.filetitle); targetUserId = findViewById(R.id.targetUserId); // 初始化目标UID输入框 imagebrowse = findViewById(R.id.imagebrowse); imageupload = findViewById(R.id.imageupload); filelogo = findViewById(R.id.filelogo); cancelfile = findViewById(R.id.cancelfile); filelogo.setVisibility(View.INVISIBLE); cancelfile.setVisibility(View.INVISIBLE); cancelfile.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { filelogo.setVisibility(View.INVISIBLE); cancelfile.setVisibility(View.INVISIBLE); imagebrowse.setVisibility(View.VISIBLE); } }); imagebrowse.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Dexter.withContext(getApplicationContext()) .withPermission(Manifest.permission.READ_EXTERNAL_STORAGE) .withListener(new PermissionListener() { @Override public void onPermissionGranted(PermissionGrantedResponse permissionGrantedResponse) { Intent intent = new Intent(); intent.setType("application/pdf"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(Intent.createChooser(intent, "Select Pdf Files"), 101); } @Override public void onPermissionDenied(PermissionDeniedResponse permissionDeniedResponse) { Toast.makeText(uploadfile.this, "需要存储权限才能选择文件", Toast.LENGTH_SHORT).show(); } @Override public void onPermissionRationaleShouldBeShown(PermissionRequest permissionRequest, PermissionToken permissionToken) { permissionToken.continuePermissionRequest(); } }).check(); } }); imageupload.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (filepath == null) { Toast.makeText(uploadfile.this, "请先选择PDF文件", Toast.LENGTH_SHORT).show(); return; } String targetId = targetUserId.getText().toString().trim(); if (targetId.isEmpty()) { Toast.makeText(uploadfile.this, "请输入目标用户UID", Toast.LENGTH_SHORT).show(); return; } processupload(filepath, targetId); // 传入目标UID } }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 101 && resultCode == RESULT_OK && data != null) { filepath = data.getData(); filelogo.setVisibility(View.VISIBLE); cancelfile.setVisibility(View.VISIBLE); imagebrowse.setVisibility(View.INVISIBLE); } } public void processupload(Uri filepath, String targetId) { final ProgressDialog pd = new ProgressDialog(this); pd.setTitle("File Uploading....!!!"); pd.show(); // 存储路径绑定目标用户,方便权限控制 final StorageReference reference = storageReference.child("user_pdfs/" + targetId + "/" + System.currentTimeMillis() + ".pdf"); reference.putFile(filepath) .addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { reference.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() { @Override public void onSuccess(Uri uri) { // 将文件信息存入目标用户的专属节点 model obj = new model(filetitle.getText().toString(), uri.toString(), currentUid, targetId, System.currentTimeMillis()); databaseReference.child(targetId).child(databaseReference.push().getKey()).setValue(obj); pd.dismiss(); Toast.makeText(getApplicationContext(), "文件已发送给目标用户", Toast.LENGTH_LONG).show(); // 重置界面状态 filelogo.setVisibility(View.INVISIBLE); cancelfile.setVisibility(View.INVISIBLE); imagebrowse.setVisibility(View.VISIBLE); filetitle.setText(""); targetUserId.setText(""); } }); } }) .addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() { @Override public void onProgress(UploadTask.TaskSnapshot taskSnapshot) { float percent = (100 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount(); pd.setMessage("Uploaded :" + (int) percent + "%"); } }); } }
关键修改点:
- 修复空指针:调整
FirebaseAuth初始化顺序,先初始化再获取当前用户 - 新增目标UID输入:添加输入框并在上传前校验是否填写
- 绑定用户存储路径:
- Storage中PDF存入
user_pdfs/{目标UID}/目录 - 数据库文件信息存入
user_files/{目标UID}/节点,确保数据和目标用户绑定
- Storage中PDF存入
- 扩展model字段:新增发送者ID、接收者ID、上传时间,方便后续管理
步骤3:Firebase安全规则配置
这是确保数据私有性的核心,必须配置规则限制非目标用户访问:
Realtime Database规则:
{ "rules": { "user_files": { "$targetUid": { ".read": "auth != null && auth.uid == $targetUid", ".write": "auth != null" // 允许所有已登录用户发送,可按需限制为特定角色 } } } }
Storage规则:
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /user_pdfs/{targetUid}/{allPaths=**} { allow read: if auth != null && auth.uid == targetUid; allow write: if auth != null; } } }
规则说明:
- 仅目标用户自身可读取属于自己的文件数据和PDF
- 所有已登录用户可发送数据,若需更严格权限可添加额外校验(如仅好友可发送)
目标用户查看数据示例
目标用户登录后,查询自身专属节点即可获取所有发送给自己的文件:
DatabaseReference userFilesRef = FirebaseDatabase.getInstance().getReference("user_files").child(currentUser.getUid()); userFilesRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { List<model> fileList = new ArrayList<>(); for (DataSnapshot ds : snapshot.getChildren()) { model file = ds.getValue(model.class); fileList.add(file); } // 用RecyclerView展示文件列表,点击可通过URL打开PDF } @Override public void onCancelled(@NonNull DatabaseError error) { Toast.makeText(context, "加载失败", Toast.LENGTH_SHORT).show(); } });
内容的提问来源于stack exchange,提问作者Jimuel Destura
相关产品推荐
相关产品推荐

