提问者:小点点

Firestore安全规则:“请求。auth。“uid”对于Android请求为空


  • Android设备:谷歌像素2
  • Android OS版本:9
  • 谷歌播放服务版本:14.3.66 (100400-213742215)
  • Firebase/Play Services SDK版本:16.0.1
  • FireBaseUI版本:ui-firelt:4.2.0,ui-auth:4.1.0.

请求。auth。uid!=null在使用Firestore安全规则时始终为null。

当uid为null时,Android客户端上的用户通过Firebase UI登录,并显示在Firestore身份验证控制台中。

service cloud.firestore {
function signedInOrPublic() {
  return request.auth.uid != null;
}

match /databases/{database}/documents {
  match /{document=**} {
    allow read;
  }
}

// Add to user collection.
match /databases/{database}/documents {
  match /users/{userId}/{collectionOrAction}/{content} {
    allow create: if signedInOrPublic();
  } 
}

该呼叫按预期工作,没有任何严格的规则设置。

usersCollection.document(userId).collection(actionCollection)
.document(content.id)
.set(ContentAction(Date(), content.id, content.title, content.creator,
content.qualityScore)).addOnSuccessListener {
updateUserActionCounter(userId, countType)
}.addOnFailureListener {
Log.w(LOG_TAG, "User content action update FAIL.")
}
implementation 'com.firebase:firebase-client-android:2.5.2'
implementation 'com.google.firebase:firebase-core:16.0.3'
implementation 'com.google.firebase:firebase-firestore:17.1.0'
implementation 'com.firebaseui:firebase-ui-firestore:4.1.0'
implementation 'com.firebaseui:firebase-ui-auth:4.0.0'

我有一个版本的谷歌服务。json用于我的调试和发布版本,以便为应用程序的生产版本保留单独的Firestore项目/环境/分析。我想知道这是否会影响Firestore规则,即使到目前为止Firebase的其他部分(Firestore db、Analytics等)都按预期运行此设置。

应用程序

应用程序

  1. 我试着检查是否有请求。Firestore规则文件中的auth不为空
  2. 我试图使用请求。auth。uid==userId,在上面比较请求的规则中。auth。uid到路径路由中的用户ID
  3. 我试图使用请求。auth。代币电子邮件==用户电子邮件,规则失败
  4. 添加额外的Firebase身份验证库,尽管我已经拥有Firebase UI身份验证库,如上图所示:implementation'com。谷歌。firebase:firebase认证:16.0。4
  5. 正在添加实现'com。谷歌。Androidgms:play services授权:16.0。1'
  6. 将Firestore库升级到firebase core:16.0。4,firebase firestore:17.1。1firebase ui firestore:4.2。0,firebase用户界面验证:4.1。0
  7. 我构建了一个简单的示例应用程序,以查看安全规则是否与简单的实现一起工作

在示例应用程序中,有一个登录/退出按钮,可根据用户当前的登录状态对其进行登录和退出。登录状态显示在左上角。“获取数据”按钮根据Firestore安全规则从Firestore数据库检索字符串字段。

2018-10-14 15:21:59.123 24192-24192/firebase_security_sample.adamhurwitz.firebasesecuritysample         
E/AndroidRuntime: FATAL EXCEPTION: main
Process: firebase_security_sample.adamhurwitz.firebasesecuritysample, PID: 24192
com.google.android.gms.tasks.RuntimeExecutionException: com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.
    at com.google.android.gms.tasks.zzu.getResult(Unknown Source:15)
    at firebase_security_sample.adamhurwitz.firebasesecuritysample.MainActivity$onCreate$2$1.onComplete(MainActivity.kt:63)
    at com.google.android.gms.tasks.zzj.run(Unknown Source:4)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:6669)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
 Caused by: com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.
    at com.google.firebase.firestore.obfuscated.zzhc.zza(com.google.firebase:firebase-firestore@@17.1.1:119)
    at com.google.firebase.firestore.obfuscated.zzk.zza(com.google.firebase:firebase-firestore@@17.1.1:134)
    at com.google.firebase.firestore.obfuscated.zzak.zza(com.google.firebase:firebase-firestore@@17.1.1:384)
    at com.google.firebase.firestore.obfuscated.zzm.zza(com.google.firebase:firebase-firestore@@17.1.1:235)
    at com.google.firebase.firestore.obfuscated.zzfv.zza(com.google.firebase:firebase-firestore@@17.1.1:7521)
    at com.google.firebase.firestore.obfuscated.zzfv$1.zza(com.google.firebase:firebase-firestore@@17.1.1:172)
    at com.google.firebase.firestore.obfuscated.zzgc.zzb(com.google.firebase:firebase-firestore@@17.1.1:3109)
    at com.google.firebase.firestore.obfuscated.zzfh.run(com.google.firebase:firebase-firestore@@17.1.1:1117)
    at com.google.firebase.firestore.obfuscated.zzfc$zza.zza(com.google.firebase:firebase-firestore@@17.1.1:67)
    at com.google.firebase.firestore.obfuscated.zzfc$zzc.zza(com.google.firebase:firebase-firestore@@17.1.1:110)
    at com.google.firebase.firestore.obfuscated.zzgv$1.onMessage(com.google.firebase:firebase-firestore@@17.1.1:107)
    at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
    at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:526)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at com.google.firebase.firestore.obfuscated.zzgf$zza.run(com.google.firebase:firebase-firestore@@17.1.1:203)
    at java.lang.Thread.run(Thread.java:764)
 Caused by: io.grpc.StatusException: PERMISSION_DENIED: Missing or insufficient permissions.
    at io.grpc.Status.asException(Status.java:534)
    at com.google.firebase.firestore.obfuscated.zzhc.zza(com.google.firebase:firebase-firestore@@17.1.1:117)
    at com.google.firebase.firestore.obfuscated.zzk.zza(com.google.firebase:firebase-firestore@@17.1.1:134) 
    at com.google.firebase.firestore.obfuscated.zzak.zza(com.google.firebase:firebase-firestore@@17.1.1:384) 
    at com.google.firebase.firestore.obfuscated.zzm.zza(com.google.firebase:firebase-firestore@@17.1.1:235) 
    at com.google.firebase.firestore.obfuscated.zzfv.zza(com.google.firebase:firebase-firestore@@17.1.1:7521) 
    at com.google.firebase.firestore.obfuscated.zzfv$1.zza(com.google.firebase:firebase-firestore@@17.1.1:172) 
    at com.google.firebase.firestore.obfuscated.zzgc.zzb(com.google.firebase:firebase-firestore@@17.1.1:3109) 
    at com.google.firebase.firestore.obfuscated.zzfh.run(com.google.firebase:firebase-firestore@@17.1.1:1117) 
    at com.google.firebase.firestore.obfuscated.zzfc$zza.zza(com.google.firebase:firebase-firestore@@17.1.1:67) 
    at com.google.firebase.firestore.obfuscated.zzfc$zzc.zza(com.google.firebase:firebase-firestore@@17.1.1:110) 
    at com.google.firebase.firestore.obfuscated.zzgv$1.onMessage(com.google.firebase:firebase-firestore@@17.1.1:107) 
    at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) 
    at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33) 
    at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:526) 
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37) 
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
    at com.google.firebase.firestore.obfuscated.zzgf$zza.run(com.google.firebase:firebase-firestore@@17.1.1:203) 
    at java.lang.Thread.run(Thread.java:764) 
service cloud.firestore {

    match /databases/{database}/documents {
        match /testCollection/testDoc {
            allow read: if request.auth.uid != null
        }
    }
}
buildscript {
ext.kotlin_version = '1.2.71'
repositories {
    google()
    jcenter()
}
dependencies {
    classpath 'com.android.tools.build:gradle:3.2.1'
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    classpath 'com.google.gms:google-services:4.1.0'

    // NOTE: Do not place your application dependencies here; they belong
    // in the individual module build.gradle files
}
}

allprojects {
repositories {
    google()
    jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 28
    defaultConfig {
       applicationId "firebase_security_sample.adamhurwitz.firebasesecuritysample"
    minSdkVersion 21
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    implementation 'com.google.android.gms:play-services-auth:16.0.1'
    implementation 'com.google.firebase:firebase-core:16.0.4'
    implementation 'com.google.firebase:firebase-auth:16.0.4'
    implementation 'com.google.firebase:firebase-firestore:17.1.1'
    implementation 'com.firebaseui:firebase-ui-firestore:4.2.0'
    implementation 'com.firebaseui:firebase-ui-auth:4.1.0'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

apply plugin: 'com.google.gms.google-services'
class MainActivity : AppCompatActivity() {

lateinit var signInStatus: TextView

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    FirebaseApp.initializeApp(
            this,
            FirebaseOptions.Builder()
                    .setApplicationId("1:63924060965:android:c387085babd1a8a4") // Required for Analytics.
                    .setApiKey("AIzaSyCi4h6WBX495xmzaRsLYro2_Vd9UcB3bpg") // Required for Auth.
                    .setDatabaseUrl("https://security-rules-sample.firebaseio.com") // Required for RTDB.
                    .setProjectId("security-rules-sample")
                    .build(),
            "firestoreSecuritySample")
    signInStatus = findViewById(R.id.signInStatus) as TextView

    val user = FirebaseAuth.getInstance().currentUser
    if (user != null) {
        signInStatus.text = user.displayName
    } else {
        signInStatus.text = "logged out"
    }

    signInButton.setOnClickListener {
        if (FirebaseAuth.getInstance().currentUser == null) {
            val providers = Arrays.asList<AuthUI.IdpConfig>(
                    AuthUI.IdpConfig.GoogleBuilder().build())

            startActivityForResult(
                    AuthUI.getInstance()
                            .createSignInIntentBuilder()
                            .setAvailableProviders(providers)
                            .build(),
                    123)
        } else {
            AuthUI.getInstance().signOut(this).addOnCompleteListener {
                signInStatus.text = "logged out"
            }
        }
    }

    getDataButton.setOnClickListener {
        FirebaseFirestore.getInstance(FirebaseApp.getInstance("firestoreSecuritySample"))
                .collection("testCollection").document("testDoc").get().addOnCompleteListener {
                    if (FirebaseAuth.getInstance().currentUser != null) {
                        firestoreResult.text = it.result!!.get("testField").toString()
                    }
                }
    }
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == 123) {
        if (resultCode == Activity.RESULT_OK) {
            val user = FirebaseAuth.getInstance().currentUser
            if (user != null) {
                signInStatus.text = user.displayName
            }
        }
    }

}

共1个答案

匿名用户

感谢Google开发者关系团队的Sam Stern帮助调试!我已经为上面创建的示例应用程序和正在生产的应用程序测试了下面的修复程序。

我很确定你的问题来自这一行:

Firebase App.get实例("firestoreSecuritySample")您正在使用自定义Firebase App与数据库通信,但登录时没有使用相同的Firebase App。每个应用实例都有一个单独的身份验证状态。

尝试更改登录代码以将应用程序传递到getInstance:

        startActivityForResult(
                // SEE BELOW FOR CHANGE
                > AuthUI.getInstance(FirebaseApp.getInstance("firestoreSecuritySample"))
                        .createSignInIntentBuilder()
                        .setAvailableProviders(providers)
                        .build(),
                123)