AngularFire: How To Access Firestore Only When Authenticated - firebase-authentication

I would like to limit Firestore access to authenticated users using AngularFire but am getting the following error:
core.js:6456 ERROR FirebaseError: Missing or insufficient permissions.
at new e (prebuilt-109c6673-0f51e182.js:188)
at prebuilt-109c6673-0f51e182.js:10416
at prebuilt-109c6673-0f51e182.js:10414
at e.onMessage (prebuilt-109c6673-0f51e182.js:10403)
at prebuilt-109c6673-0f51e182.js:10356
at prebuilt-109c6673-0f51e182.js:10387
at prebuilt-109c6673-0f51e182.js:15194
at ZoneDelegate.invoke (zone.js:372)
at Zone.run (zone.js:134)
at zone.js:1276
I created a very basic test application to test this.
app.component.html
<ng-container *ngIf="auth.user | async as user; else showLogin">
<ul>
<li *ngFor="let profile of profiles | async">{{profile.DisplayName}}</li>
</ul>
</ng-container>
<ng-template #showLogin>
<p>You must sign in to continue.</p>
<button (click)="signIn()"> SIGN IN </button>
</ng-template>
app.component.ts
import { Component } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
import { AngularFireAuth } from '#angular/fire/auth';
import { Observable } from 'rxjs';
import firebase from 'firebase/app';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'test-auth';
profiles: Observable<any[]>;
constructor (
public auth: AngularFireAuth,
private firestore: AngularFirestore) {
this.profiles = firestore.collection('UserProfiles').valueChanges();
}
signIn(): void {
this.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
signOut(): void {
this.auth.signOut();
}
}
My Firestore Rules
If the read rule is changed to only "allow read;" the application above works as expected.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents/{document=**} {
allow read: if request.auth != null;
allow write: if request.auth != null;
}
}
My Versions
Angular CLI: 12.0.3
Node: 14.17.0
Package Manager: npm 7.13.0
OS: linux x64
Angular: 12.0.3
... animations, cli, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Package Version
---------------------------------------------------------
#angular-devkit/architect 0.1200.3
#angular-devkit/build-angular 12.0.3
#angular-devkit/core 12.0.3
#angular-devkit/schematics 12.0.3
#angular/fire 6.1.5
#schematics/angular 12.0.3
rxjs 6.6.7
typescript 4.2.4
$ firebase --version
9.12.1
However - raw Firebase works as expected.
With the following code, I have isolated this issue to (1) a bug (?) in AngularFire or (2) my inability to properly implement AngularFire in the code provided in my prior comment.
app.component.ts
import { Component, OnDestroy, OnInit } from '#angular/core';
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
export interface ProfileModel {
Id: string,
DisplayName: string
}
export interface CurrentUser {
uid: string;
name?: string;
email?: string;
}
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnDestroy, OnInit {
title = 'test-auth';
currentUser: CurrentUser | null = null;
profilesArray: ProfileModel[] = [];
fb: firebase.app.App;
fs: firebase.firestore.Firestore;
profilesCollection: firebase.firestore.CollectionReference<firebase.firestore.DocumentData>;
unsubscribe?: firebase.Unsubscribe;
constructor () {
this.fb = firebase.initializeApp({
apiKey: "OMITTED",
authDomain: "angularfiretestapp.firebaseapp.com",
databaseURL: "https://angularfiretestapp.firebaseio.com",
projectId: "angularfiretestapp",
storageBucket: "angularfiretestapp.appspot.com",
messagingSenderId: "OMITTED",
appId: "OMITTED",
measurementId: "OMITTED"
});
this.fs = firebase.firestore();
this.profilesCollection = this.fs.collection('UserProfiles');
}
ngOnDestroy():void {
if (this.unsubscribe) {
this.unsubscribe();
}
}
ngOnInit():void {
this.unsubscribe = this.fb.auth().onAuthStateChanged(authUser => {
if (authUser) {
this.currentUser = {
uid: authUser.uid,
name: authUser.displayName ? authUser.displayName : '',
email: authUser.email ? authUser.email : ''
};
this.profilesArray = [];
this.profilesCollection.get().then(qSnap => {
qSnap.forEach(doc => {
this.profilesArray.push({
Id: doc.id,
DisplayName: doc.get('DisplayName')
});
});
});
} else {
this.currentUser = null;
}
});
}
signIn(): void {
this.fb.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider());
}
signOut(): void {
this.fb.auth().signOut();
}
}
app.component.html
<ng-container *ngIf="currentUser; else showLogin">
<p>Here are some profiles:</p>
<ul>
<li *ngFor="let profile of profilesArray">{{profile.DisplayName}}</li>
</ul>
<button (click)="signOut()"> SIGN OUT </button>
</ng-container>
<ng-template #showLogin>
<p>You must sign in to continue.</p>
<button (click)="signIn()"> SIGN IN </button>
</ng-template>
Posted Elsewhere
Issue 2838 filed on GitHub.
Also posted on Reddit.
My code is available in this GitHub repository.

In your constructor it should look more like this
auth.onAuthStateChanged((user) => {
if (user && user.emailVerified) {
this.profiles = firestore.collection('UserProfiles').valueChanges();
} else {
signIn();
}
});
If it still throws exceptions you could try downgrading firebase to 8.3.0.

Related

AWS Cognito UI configured using Amplify in quasar/Vue3 doesn't show Facebook login button

I'm using amplify to add auth UIs for AWS Cognito to my quasar/Vue3 website.
I used amplify import auth since I already have Cognito userpool configured sepratly.
Here is my sample App.vue
<template>
<div id="q-app">
<div>
<div v-if="authState !== 'signedin'">You are signed out.</div>
<amplify-authenticator :federated="federatedIds">
<div v-if="authState === 'signedin' && user">
<div>Hello, {{user.username}}</div>
</div>
<amplify-sign-out></amplify-sign-out>
</amplify-authenticator>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from '#vue/composition-api'
import { onAuthUIStateChange } from '#aws-amplify/ui-components'
export default defineComponent({
name: 'App',
created() {
this.unsubscribeAuth = onAuthUIStateChange((authState, authData) => {
this.authState = authState;
this.user = authData;
})
},
data() {
return {
user: undefined,
authState: undefined,
unsubscribeAuth: undefined,
federatedConfig: { provider: "Facebook" },
federatedIds: {
facebookAppId: "*******"
}
}
},
beforeUnmount() {
this.unsubscribeAuth();
}
})
</script>
Here is my boot file:
import Amplify from 'aws-amplify';
import awsconfig from '../aws-exports';
import {
applyPolyfills,
defineCustomElements,
} from '#aws-amplify/ui-components/loader';
applyPolyfills().then(() => {
defineCustomElements(window);
});
Amplify.configure(awsconfig);
I have spent hours looking for a solution, here are a few links
https://www.npmjs.com/package/#aws-amplify/ui-components#vue
https://github.com/aws-amplify/amplify-js/issues/3818
Amplify federated buttons not showing up
In case someone faces similar issue, you need to add .prop for amplify's properties:
<amplify-authenticator :federated="federatedIds"> has to change to <amplify-authenticator :federated.prop="federatedIds">
I had to do the same thing for
<amplify-sign-up slot="sign-up" username-alias="email" :form-fields.prop="formFields">
</amplify-sign-up>
Reference: https://github.com/aws-amplify/amplify-js/issues/5298#issuecomment-621124576

Getting data in Console but cant All display in ionic 5 angular

I'm using ionic 5 and angular 11 for front-end and for back-end laravel api crud,
for my back-end it works good
I could not get any error in this problem I cant display data in page but I get it in console
this is my page annonce.ts**
import { Component, OnInit } from '#angular/core';
import { AnnonceService } from '../annonce.service';
#Component({
selector: 'app-annonce',
templateUrl: './annonce.page.html',
styleUrls: ['./annonce.page.scss'],
})
export class AnnoncePage implements OnInit {
productData:any;
constructor(
private service:AnnonceService,
) { }
ngOnInit() {}
ionViewWillEnter(){
this.getAllProduct()
}
getAllProduct(){
this.service.getAllProduct().subscribe(res=>{
console.log(res)
this.productData=res
this.productData = Array.of(this.productData);
})
}
deleteProduct(id){
this.service.deleteProduct(id).subscribe(res=>{
console.log(res)
this.productData=res
//mise a jour d'annonce
this.getAllProduct()
})
}
}
and this is annonce.service.ts
getAllProduct(): Observable<Product>{
return this.http.get<Product>(this.api_URL).pipe(retry(2), catchError(this.handleError)) }
and this is annonce.html
<ion-list>
<ion-item-sliding *ngFor="let item of productData">
<ion-item>
<ion-label>
<h2>{{item.title}}</h2>
<h2>{{item.descripton}}</h2>
<p>{{item.price}}</p>
</ion-label>
<ion-note slot="end">
detailleProduct
</ion-note>
</ion-item>
<ion-item-options>
<!--edit-->
<ion-item-option>
<ion-icon slot="icon-only" name="create" [routerLink]="['/','edit-annonce', item.id]"> </ion-icon>
</ion-item-option>
<!--delete-->
<ion-item-option color="danger">
<ion-icon slot="icon-only" name="trash" (click)="deleteProduct(item.id)"> </ion-icon>
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
image of browser
I guess your this.productData is not properly handled. In your response you get this data which you logged to the console and assign to this.productData:
{
data: [{...}] some array,
links: {...},
meta: {...}
} // response object
In the next line this.productData = Array.of(this.productData); you assign this to this.productData (remark the []):
[{
data: [{...}],
links: {...},
meta: {...}
}]
// array of responses
You probably want to do this to get your data out of the response
this.productData = res.data;

Ionic PDFJS Cannot match any routes. URL Segment: 'lib/ui/index.html'

I am trying to open a pdf in my ionic 5 application with the plugin
npm i # pdftron / pdfjs-express --save
but ionic shows me the error Cannot match any routes. URL Segment: 'lib / ui / index.html'
please how to correct this error?
my code:
app.component.html
<div class="page">
<div class="header">Angular sample</div>
<div #viewer class="viewer"></div>
</div>
app.component.ts
import { Component, ViewChild, OnInit, ElementRef, AfterViewInit } from '#angular/core';
import WebViewer from '#pdftron/pdfjs-express';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit {
#ViewChild('viewer', { static: false }) viewer: ElementRef;
wvInstance: any;
ngAfterViewInit(): void {
WebViewer({
path: '../lib',
initialDoc: '../files/webviewer-demo-annotated.pdf'
}, this.viewer.nativeElement).then(instance => {
this.wvInstance = instance;
})
}
ngOnInit() {
}
}
Have you used any of our angular samples here https://github.com/PDFTron?q=angular? You can clone one of the samples and take a look at how it is implemented

How to pass value from template HTML to component to then be used in service

I want to fetch id from component.html into component.ts to pass it to a service.
.ts file is;
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http'
import { HttpErrorResponse } from '#angular/common/http/src/response';
import { SendUsingApiService } from '../send-using-api.service';
import { Router, ActivatedRoute } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { setDefaultService } from 'selenium-webdriver/chrome';
#Component({
selector: 'app-org-info',
templateUrl: './org-info.component.html',
styleUrls: ['./org-info.component.css'],
providers: [SendUsingApiService]
})
export class OrgInfoComponent implements OnInit {
orgData: string[] = [];
Id = 1;
editRecord:FormGroup;
constructor(private httpService: HttpClient, private _serv: SendUsingApiService,
private fb: FormBuilder, private _ar:ActivatedRoute, private _r:Router) {
this.editRecord = this.fb.group({
Id:['1', []],
OrganisationName:['', []],
ContactPerson:['', []],
ContactPersonHPNo:['', []],
ContactPersonEmailId:['', []]
});
}
ngOnInit() {
console.log(this._ar.snapshot.params.Id, "+ve");
this._ar.params.subscribe(() => {
this._serv.getUsers(this._ar.snapshot.params.Id).subscribe((res)=>{
console.log(res);
this.setUser(res);
});
});
}
I am getting the value for console.log(this._ar.snapshot.params.Id); as undefined "+ve".
I want to get the Id value in console.
As per requests I am adding html part, though little adjusted;
<td style="text-align: center;">
<a class="btn btn-basic" [routerLink]="['/org-info',data['Id']]" role="button" (click)="getOrgData(data.Id)">View</a>
</td>
I defined a property instead of Id = 1; (above)
paramId = '';
then, within ngOnInit;
ngOnInit() {
this.paramId = this._ar.snapshot.params.Id;
console.log(paramId, "+ve");
}
Doing this, I got the Id value instead of undefined.

*ngIf works OK in some parts, but not in others. Angular 2.0.x

I am trying to use *ngIf in a simple component and angular is throwing an error on *ngIf.
Removing the "*ngIf="loggedIn" and it runs. {{loggedIn}} shows true after logging in and false before.
The main app uses the same div to enable menus, which works fine.
I must be doing some simple wrong but it escapes me.
thanks
First the error:
Can't bind to 'ngIf' since it isn't a known property of 'div'. ("<div [ERROR ->]*ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:5
Property binding ngIf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:0 ; Zone: <root> ; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors:
Can't bind to 'ngIf' since it isn't a known property of 'div'. ("<div [ERROR ->]*ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:5
Property binding ngIf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section. ("[ERROR ->]<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
"): ShowConfigComponent#0:0
at TemplateParser.parse (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:8446:21)
at RuntimeCompiler._compileTemplate (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16824:53)
at eval (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16746:85)
at Set.forEach (native)
at compile (http://127.0.0.1:8080/node_modules/#angular/compiler/bundles/compiler.umd.js:16746:49)
at ZoneDelegate.invoke (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:203:28)
at Zone.run (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:96:43)
at http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:462:57
at ZoneDelegate.invokeTask (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:236:37)
at Zone.runTask (http://127.0.0.1:8080/node_modules/zone.js/dist/zone.js:136:47)
Template:
<div *ngIf="loggedIn">
<div class='panel panel-primary'>
<div class='panel-heading' >
Shows Configuration {{loggedIn}}
</div>
</div>
Component:
import { Component, OnInit } from '#angular/core';
import { IShowConfig } from './iShowConfig';
import { AuthService } from '../../shared/AuthService';
import { BrowserModule } from '#angular/platform-browser';
#Component({
// selector: 'showconfig',
templateUrl: 'app/showMenu/showConfig/ShowConfig.component.html'
})
export class ShowConfigComponent implements OnInit {
pageTitle: string = 'Product List';
imageWidth: number = 50;
imageMargin: number = 2;
showImage: boolean = false;
listFilter: string = '';
errorMessage: string;
shows: IShowConfig[];
public isLoggedIn: boolean = true;
// constructor(private _productService: ProductService) {
constructor(public authSvc: AuthService) {
this.isLoggedIn = true;
console.log(`config loggedIn: `);
console.log(`${AuthService.isLoggedIn}`);
if (authSvc.user === undefined) {
console.log('islogin undefine');
} else {
console.log('config user: ' + authSvc.user);
}
console.log('show config count: ' + AuthService.count);
}
public get loggedIn(): boolean {
if (AuthService.isLoggedIn) {
return true;
} else {
return false;
}
}
toggleImage(): void {
this.showImage = !this.showImage;
}
ngOnInit(): void { }
onRatingClicked(message: string): void {
this.pageTitle = 'Show List: ' + message;
}
}
I found the solution! I think Nicu also guessed what it was.
I didn't import BrowserModule into my ShowConfig.module.ts ie: my #ngmodule.
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { ShowConfigComponent } from './ShowConfig.component';
import { AuthService } from '../../shared/AuthService';
import { BrowserModule } from '#angular/platform-browser';**
#NgModule({
imports: [
// The following line was missing
BrowserModule,
FormsModule
],
declarations: [
ShowConfigComponent
],
providers: [
]
})
export class ShowConfigModule { }