Angular和Firestore:FirebaseError:缺少权限或权限不足.如何在观察特定文档的同时添加idToken [英] Angular and Firestore: FirebaseError: Missing or insufficient permissions. How add idToken while observing a specific document

查看:81
本文介绍了Angular和Firestore:FirebaseError:缺少权限或权限不足.如何在观察特定文档的同时添加idToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对以实时方式通知的以下代码进行编码.我的意思是它一直在观察,并且很快任何收集字段都被更新,它被加载到Angular页面中.

I code the code bellow that is notified in real time manner. I mean it keeps observing and soon any collection fields are updated it is loaded in Angular page.

app.component.ts

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

app.component.html

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

我的问题是,在使用db.collection().valueChanges()或snapshotChanges()进行观察时,我不知道如何添加idToken.好吧,我知道如何从应用程序令牌中从应用程序外部生成idToken,对于这个问题,我只想重点介绍如何在侦听"特定文档的valueChanges()或snapshotChanges()的同时添加此类idToken.想象每个文档都是不同的事务,仅对单个用户感兴趣.

My problem is that I don't know how to add an idToken while observing with either db.collection().valueChanges() or snapshotChanges(). Well, I know how generate the idToken outside the application from a Custom Token and for this question I want to focus only how to add such idToken while "listening" valueChanges() or snapshotChanges() of a specific document. Imagine each document is a diferent transaction interested only to a single user.

如果我将Firestore规则更改为允许所有人读取",则上面的代码可以按预期工作,但是我想找到某种方式,仅允许Angular通过idToken读取,最重要的是,观察单个文档的更改而不是像上面的代码那样观察整个集合中的所有文档.

The above code works as expected if I change the Firestore rules to "allow read to all" but I want to find someway to only allow Angular to read if it pass the idToken and, on top of that, observe single document changes instead of observe all documents from an entire collection as code above does.

这里有一些尝试性的尝试,只是为了举例说明我在尝试什么.我不知道如何在其中任何一个中添加idToken.我还添加了一个我想象中的示例,如果没有AngularFire,它可以工作.我想我对这里的三点感到困惑:

Here are some tentatives failling just to exemplify what I am trying. I don't know how to add idToken in any of them. I added also an example what I am imagining could work without AngularFire. I guess I am confused about three points here:

  • 一些非常基本的想法,如何观察/收听单个文档

  • some very basic idea how to observe/listen a single document

如何添加与curl/postman相似的idToken

how add a idToken similar as I do with curl/postman

无法收听/观察单个文档.我必须观察整个收集和过滤.

it isn't possible to listen/observe a single document. I must observe entire collection and filter.

暂定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();

不带AngularFire的暂定4

Tentative 4 without 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;
  })
}

预期的行为是监听特定文档的更改并更新前端,例如:

And the expected behaviour is listening for a especific document be changed and update front end like:

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

最后,如果要在此处添加,我可以使用此curl查询单个文档.显然,它不是在监听/观察文档.它只是检索它.

Finally, in case it adds here, I can query a single document with this curl. Obvisouly it is not listening/observing the document. It just retrieves it.

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的两个建议进行编辑.

*** edited After gso_Gabriel's two suggestions.

第一次建议)

我尝试遵循 https://github.com/angular/angularfire/issues/2109 .好吧,这似乎是对新功能的建议,而不是对当前功能的建议.顺便说一句,我尝试了:

I tried follow https://github.com/angular/angularfire/issues/2109. Well it seems to be a suggestion for new feature than really a current alternative. BTW, I gave a try with:

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

sDme6IRIi4ezfeyfrU7y代表一个特定的文档,但是我从传输集合中获取了所有文档(与this.transfers = db.collection('/transfer').valueChanges();相同的行为)

sDme6IRIi4ezfeyfrU7y stands for a specific document but I got all documents from transfer collection (same behaviour as 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 };
      });
    });
}

这行得通.我可以看到应用了过滤器"where"(... ref => ref.where("id","==","1")

This worked. I can see the filter "where" is applied (... ref => ref.where("id", "==", "1")

现在我不知道如何使用自定义Tokem生成的idToken.我想它一定存在,就像我们使用HttpClient一样(请参阅上面的Tentative 4,了解什么是标头的常用方法).

Now I am missing how to use the idToken resulted from Custom Tokem. I guess it must exist someway like we do with HttpClient (see my Tentative 4 above to understand what is common approach with header).

***如果要在此处添加某种方式,即使有人在github上发布类似的问题也没有得到任何评论,只是有人说正在寻找相同的答案

*** In case it add somehow here, even the similar question posted on github didn't get any comment other than someone saying is looking for same answer https://github.com/angular/angularfire/issues/2419

***感谢gstvg的最终解决方案

*** FINAL SOLUTION THANKS TO 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 };
      });
    });

  }

}

推荐答案

firestore客户端auth由firebase auth处理,因此,要进行经过身份验证的调用,您必须在前端使用firebase auth进行身份验证,并在上生成自定义令牌后端,使用firebase.auth.signinWithCustomToken(customToken):

The firestore client auth is handled by firebase auth, so, to make authenticated calls, you must authenticate with firebase auth on the frontend, with your custom token generated on the backend, using 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

这篇关于Angular和Firestore:FirebaseError:缺少权限或权限不足.如何在观察特定文档的同时添加idToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆