Angular и Firestore: FirebaseError: Отсутствует или недостаточно разрешений. Как добавить idToken при соблюдении указанного c документа - PullRequest
1 голос
/ 22 апреля 2020

Я кодирую код ниже, который уведомляется в режиме реального времени. Я имею в виду, что он продолжает наблюдать, и вскоре все поля коллекции обновляются, он загружается на страницу Angular.

app.component.ts

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

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

  constructor(db: AngularFirestore) {
    this.transfers = db.collection('/transfer').valueChanges();
  }

}

app.component. html

<code><ul>
  <li *ngFor="let transfer of transfers | async">
    <pre>{{ transfer | json }}

Моя проблема является то, что я не знаю, как добавить idToken при наблюдении либо с помощью db.collection (). valueChanges () или snapshotChanges (). Что ж, я знаю, как генерировать idToken вне приложения из пользовательского токена, и для этого вопроса я хочу сосредоточиться только на том, как добавить такой idToken при «прослушивании» valueChanges () или snapshotChanges () указанного c документа. Представьте, что каждый документ представляет собой отдельную транзакцию, интересующую только одного пользователя.

Приведенный выше код работает, как и ожидалось, если я изменю правила Firestore на «разрешить чтение всем», но я хочу найти способ разрешить только Angular читать, если он проходит через idToken, и, кроме того, наблюдать за изменениями в одном документе вместо того, чтобы наблюдать за всеми документами из всей коллекции, как это делает код выше.

Вот некоторые предварительные предположения, проваливающиеся просто для иллюстрации того, что я пытаюсь сделать. Я не знаю, как добавить idToken в любой из них. Я добавил также пример того, что, по моему мнению, может работать без AngularFire. Я предполагаю, что меня смущают три момента:

  • какая-то очень базовая c идея, как наблюдать / прослушать один документ

  • как добавить idToken, похожий на то, как я делаю с curl / postman

  • , невозможно прослушать / наблюдать один документ. Я должен наблюдать всю коллекцию и фильтр.

Предварительно 1:

this.uniqueTransfer = db.collection('/transfer',
  ref => ref.where("id", "==", "1"))
  .snapshotChanges().pipe(map(actions => actions.map(a => a.payload.doc.data()))
  );;

Предварительно 2:

this.uniqueTransfer = db.collection('/transfer', ref => ref.where("id", "==", "1")).snapshotChanges().pipe(
  map(actions => actions.map(a => {
    const data = a.payload.doc.data();
    return { data };
  }))

Предварительно 3:

db.doc(`transfer/Wsj0dysyHHok3xupwDhD`) //this is the id copied from Firebase console
  .snapshotChanges()
  .pipe()
  .subscribe();

Предварительно 4 без AngularFire

constructor(private http: HttpClient) {
  this.getTranfers();
}

public getTranfers() {

  const headers = { 'Authorization': 'valid idtoken working with curl' }
  const body = JSON.stringify({
    "structuredQuery": {
      "where": {
        "fieldFilter": {
          "field": { "fieldPath": "id" },
          "op": "EQUAL",
          "value": { "stringValue": "4" }
        }
      },
      "from": [{ "collectionId": "transfer" }]
    }
  })

  this.http.post<any>('https://firestore.googleapis.com/v1/projects/firetestjimis/databases/(default)/documents:runQuery', body, { headers }).subscribe(data => {
    this.uniqueTransfer = data;
  })
}

И ожидаемое поведение - прослушивание для изменения документа especifi c и обновление внешнего интерфейса, например:

<div>{{(uniqueTransfer|async)?.status}}</div>

Наконец, в случае добавления здесь, я можно запросить один документ с этим curl. Obvisouly это не слушать / наблюдать документ. Он просто получает его.

curl --location --request POST 'https://firestore.googleapis.com/v1/projects/firetestjimis/databases/(default)/documents:runQuery' \
--header 'Authorization: Bearer certain idToken resulted from a Custom Token' \
--header 'Content-Type: application/json' \
--data-raw '{
"structuredQuery": {
    "where" : {
        "fieldFilter" : { 
        "field": {"fieldPath": "id"}, 
        "op":"EQUAL", 
        "value": {"stringValue": "1"}
        }
    },
    "from": [{"collectionId": "transfer"}]
    }
}'

*** отредактировано После двух предложений gso_Gabriel.

FIRST SUGGESTION)

Я пытался следовать https://github.com/angular/angularfire/issues/2109 , Что ж, похоже, это предложение для новой функции, а не действующая альтернатива. Кстати, я дал попробовать с:

this.transfers = db.doc<any>(`transfer/sDme6IRIi4ezfeyfrU7y`).valueChanges();

sDme6IRIi4ezfeyfrU7y обозначает конкретный c документ, но я получил все документы из коллекции передачи (такое же поведение, как this.transfers = db.collection ('/ Transfer' ) .valueChanges ();)

ВТОРОЕ ПРЕДЛОЖЕНИЕ)

import { map } from 'rxjs/operators';
import 'rxjs/Rx';

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

  transferCollectionRef: AngularFirestoreCollection<any>;

  constructor(db: AngularFirestore) {

    this.transferCollectionRef = 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();// as Todo;
        const id = action.payload.doc.id;
        return { id, ...data };
      });
    });
}

Это сработало. Я вижу фильтр "где" применяется (... ref => ref.where ("id", "==", "1")

Теперь мне не хватает как использовать полученный idToken от Custom Tokem. Я думаю, что он должен существовать каким-то образом, как мы делаем с HttpClient (см. мой предварительный 4 выше, чтобы понять, что является общим подходом с заголовком).

*** В случае, если это добавить как-то здесь, даже аналогичные вопрос, размещенный на github, не получил никакого комментария, кроме того, что кто-то говорит, что ищет тот же ответ https://github.com/angular/angularfire/issues/2419

*** ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ СПАСИБО gstvg

export class AppComponent {
  public transfers: Observable<any[]>;

  transferCollectionRef: AngularFirestoreCollection<any>;

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

  async listenAllTransfersWithToken() {
    await this.auth.signInWithCustomToken("eyJh...w8l-NO-rw");
    this.transfers = this.db.collection('/transfer').valueChanges();
  }

  async listenSingleTransferWithToken() {
    await this.auth.signInWithCustomToken("eyJ...w8l-NO-rw");
    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 };
      });
    });

  }

}

1 Ответ

1 голос
/ 01 мая 2020

Аутентификация клиента firestore обрабатывается аутентификацией firebase, поэтому для выполнения аутентифицированных вызовов вы должны пройти аутентификацию с firebase auth на внешнем интерфейсе, с вашим собственным токеном, сгенерированным на бэкенде, с использованием firebase.auth.signinWithCustomToken (customToken):

import { Component } from '@angular/core';
import { Observable } from 'rxjs';
import { AngularFireAuth } from '@angular/fire/auth';
import { auth } from 'firebase/app';
import { AngularFirestore } from '@angular/fire/firestore';

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

  constructor(db: AngularFirestore, public auth: AngularFireAuth) {
    await auth.signinWithCustomToken(customToken);
    this.transfers = db.collection('/transfer').valueChanges();
  }

}

https://firebase.google.com/docs/reference/js/firebase.auth.Auth#signinwithcustomtoken

https://github.com/angular/angularfire/blob/master/docs/auth/getting-started.md

...