【问题标题】:Android with Firestore enabled: com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions启用了 Firestore 的 Android:com.google.firebase.firestore.FirebaseFirestoreException:PERMISSION_DENIED:缺少权限或权限不足
【发布时间】:2020-09-08 15:01:08
【问题描述】:

首先,我找到了很多关于这个问题的答案,建议在 Firestore 规则中删除 autentication。这当然不是我想要的。

我的 Firestore 规则是

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    match /{document=**} {
      allow read, update, write: if request.auth.uid != null;
    }
  }
}

而且我确实希望保留一定程度的授权。

我的安卓代码是:

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.firestore.FirebaseFirestore

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val db = FirebaseFirestore.getInstance()

        val TAG = "MainActivity"

        db.collection("transfer")
            .get()
            .addOnSuccessListener { result ->
                for (document in result) {
                    Log.d(TAG, "${document.id} => ${document.data}")
                }
            }
            .addOnFailureListener { exception ->
                Log.w(TAG, "Error getting documents.", exception)
            }
    }
}

Android 项目包含直接从 Firestore 下载的 google-service.json

{
  "project_info": {
    "project_number": "7953 *** 50",
    "firebase_url": "https://firetestjimis.firebaseio.com",
    "project_id": "firetestjimis",
    "storage_bucket": "firetestjimis.appspot.com"
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:795 *** bb2ec8dc810f",
        "android_client_info": {
          "package_name": "com.example.demo"
        }
      },
      "oauth_client": [
        {
          "client_id": "7953 **** sdu68ociuueir.apps.googleusercontent.com",
          "client_type": 3
        }
      ],
      "api_key": [
        {
          "current_key": "AIza **** qHqOyrBsr_0cs_uq8"
        }
      ],
      "services": {
        "appinvite_service": {
          "other_platform_oauth_client": [
            {
              "client_id": "795 **** rkemu101gg0o.apps.googleusercontent.com",
              "client_type": 3
            }
          ]
        }
      }
    }
  ],
  "configuration_version": "1"
}

我的最终目标是实现与使用 Angular 但使用 Android/Kotlin 相同的目标。举例来说,我的工作 Angular 代码是:

app.component.ts

import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore';

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
import 'rxjs/Rx';

import { AngularFireAuth } from '@angular/fire/auth';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  public transfers: Observable<any[]>;

  transferCollectionRef: AngularFirestoreCollection<any>;

  constructor(public auth: AngularFireAuth, public db: AngularFirestore) {
    this.listenSingleTransferWithToken();
  }


  async listenSingleTransferWithToken() {
    await this.auth.signInWithCustomToken("eyJ **** a custom token **** bdaG1Q");
    this.transferCollectionRef = this.db.collection<any>('transfer', ref => ref.where("id", "==", "1"));
    this.transfers = this.transferCollectionRef.snapshotChanges().map(actions => {
      return actions.map(action => {
        const data = action.payload.doc.data();
        const id = action.payload.doc.id;
        return { id, ...data };
      });
    });

环境.ts

export const environment = {
  production: false,
  firebaseConfig: {
    apiKey: "AI yyy ihK3xs",
    authDomain: "firetestjimis.firebaseapp.com",
    databaseURL: "https://firetestjimis.firebaseio.com",
    projectId: "firetestjimis",
    storageBucket: "firetestjimis.appspot.com",
    messagingSenderId: "79 www 350",
    appId: "1:xxx dc810f"
  }
};

      }

所以我的直截了当的问题是:我缺少什么才能使上面的 kotlin 代码正确识别?也许这与 Angular 的想法相同,我只需要在调用期间添加一个自定义令牌,但如何在 Android/kotlin 中做到这一点?

***已编辑

NodeJs 服务器提供了一个 CustomToken 成功地在 Angular 上运行,但我想念在 Android/Kotlin 中如何做同样的事情

const admin = require('firebase-admin');

exports.serviceAccount = {
  "type": "service_account",
  "project_id": "firetestjimis",
  "private_key_id": "ecfc6 *** e6661fd05923",
  "private_key": "-----BEGIN PRIVATE KEY-----\ *** REMOVED *** ==\n-----END PRIVATE KEY-----\n",
  "client_email": "firebase-adminsdk-fg6p9@firetestjimis.iam.gserviceaccount.com",
  "client_id": "1024 *** 38150",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fg6p9%40firetestjimis.iam.gserviceaccount.com"
}

 admin.initializeApp({
   credential: admin.credential.cert(exports.serviceAccount)
});

var uid = "NSB *** 4DRo2"; //copied from https://console.firebase.google.com/project/firetestjimis/authentication/users
var claim = {
  control: true
};
admin.auth().createCustomToken(uid)
  .then(function (customToken) {
    console.log(customToken)
  })
  .catch(function (error) {
    console.log("Error creating custom token:", error);
  });

***已编辑

【问题讨论】:

  • 您在 Android 应用程序中的何处验证用户身份?
  • @RosárioPereiraFernandes,我不打算在 Adroid 中对用户进行身份验证。它将从内部端点接收 CustomToken。内部端点是指托管在我们的 DataCenter 中的 NodeJs 服务器,它将响应我们的 Android 应用程序,然后,使用这个 CustonToken,应用程序可以开始监听一个集合文档(您可以在上面的 Angular 中看到它的工作)。我编辑了我的问题,添加了提供 CustomToken 的 NodeJ,尽管我认为它并不相关。基于相同的 Angular 方法,你知道如何在 Android/Kotlin 中“signInWithCustomToken”然后“snapshotChanges()”吗?
  • @RosárioPereiraFernandes 我刚刚从我的 Android Studio 添加了一个打印屏幕,其中显示了 CustomToken 已验证并且已登录。但是如何监听/观察/快照更改集合文档?

标签: android angular firebase kotlin google-cloud-firestore


【解决方案1】:

这是我目前的解决方案。希望它可以帮助未来的读者。请注意,这是我在 Firestore 和 Android/Kotlin 中的第一个项目。如果您在下面看到一些奇怪的方法,请告诉我。

package com.example.demo
//https://developer.android.com/training/basics/firstapp/starting-activity
//https://firebase.google.com/docs/firestore/quickstart#kotlin+ktx

// Tutorial to CustomToken
//https://firebase.google.com/docs/auth/android/custom-auth#kotlin+ktx

//Tutorial to Snatshot Listeners and its queries
//https://firebase.google.com/docs/firestore/query-data/listen#kotlin+ktx

import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FirebaseFirestore

class MainActivity : AppCompatActivity() {

    lateinit var auth: FirebaseAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        val TAG = "MainActivity"
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        auth = FirebaseAuth.getInstance()

        auth.signInWithCustomToken("ey *** uHUrg")
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    Log.d(TAG, "*** signInWithCustomToken:success")
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.exception)
                    Toast.makeText(
                        baseContext, "Authentication failed.",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            }

        //val db = FirebaseFirestore.getInstance()

        FirebaseFirestore.getInstance().collection("transfer")
            .whereEqualTo("id", "1")
            .addSnapshotListener { value, e ->
                if (e != null) {
                    Log.w(TAG, "Listen failed.", e)
                    return@addSnapshotListener
                }

                val transfer = ArrayList<String>()
                for (doc in value!!) {
                    doc.getString("status")?.let {
                        transfer.add(it)
                    }
                }
//                for (document in value) {
//                    Log.d(TAG, "${document.id} => ${document.data}")
//                }
                Log.d(TAG, "*** transfer: $transfer")
            }
    }

}

【讨论】:

    【解决方案2】:

    在您的 Firestore 规则中更改自

    allow read, update, write: if request.auth.uid != null;
    

    allow read, write: if true;
    

    这将修复崩溃和丢失的权限

    【讨论】:

      猜你喜欢
      • 2018-04-25
      • 2019-02-26
      • 2022-01-25
      • 1970-01-01
      • 2020-09-01
      • 2021-12-31
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多