简体   繁体   中英

Firebase throws insufficient permissions when using getServerSideProps in my Next.js app

im trying to create a chat app. When a user heads to the url www.myproject.com/chat/[id] it will go get the conversation data.

My security rules are fine, however changing the rules to completely open ( allow read, write; ) fixes the problem. So this means that the current users auth state must be null at the time of trying to get the data (even though the user is logged in).

Here is my [conversationid].tsx:

import React from "react";
import Head from "next/head";
import Navbar from "../../components/Navbar/Navbar";
import Footer from "../../components/Footer/Footer";
import Chat from "../../components/Chat/Chat";
import { getConversationData } from "../../services/firebase";

export async function getServerSideProps(context) {
  const response = await getConversationData(context.params.conversationid);
  if (response.success) {
    return {
      props: {
        conversationData: response.conversation,
      },
    };
  } else {
    return {
      notFound: true,
    };
  }
}

function Page({ conversationData }) {
  return (
    <>
      <Head>
        <title>Chat</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Navbar page={"Profile"} />
      <Chat conversation={conversationData} />
      <Footer />
    </>
  );
}

export default Page;

The service function that gets the conversation data looks like this:

export async function getConversationData(conversationID: string) {
  const db = getFirestore(firebaseApp);
  const conversationDoc = doc(db, "conversations", conversationID);
  const response = await getDoc(conversationDoc);
  if (response.exists) {
    return {
      success: true,
      conversation: response.data(),
    };
  } else {
    return {
      success: false,
      conversation: null,
    };
  }
}

I am still new to NEXT and handling this workflow of getting data from the server before loading the page is unfamiliar for me, I just learnt React recently. In those apps, handling the auth state hasn't been an issue for me before.

Im guessing I have to wait until the auth state is available? Or is cookies something that can be used? Unsure of the usual approach to handling this problem.

Here is my security rules. The one in question is /conversation/{conversationID} and the {message} rule below it:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /listings/{listingID} {
      allow read;
      allow update: if request.auth != null;
      allow write: if request.auth != null && request.auth.uid == resource.data.seller
      allow create: if request.auth != null;
    }
        match /listings/{listingID}/comments/{comment} {
      allow read; 
      allow write, create: if request.auth != null;
    }
    match /listings/{listingID}/comments/{comment}/replies/{reply} {
      allow read; 
      allow write, create: if request.auth != null;
    }
    match /users/{userID} {
      allow read;
      allow update: if (request.resource.data.diff(resource.data).affectedKeys()
        .hasOnly(['notifications'])) && request.auth != null;
      allow write: if request.auth != null && request.auth.uid == userID;
      allow create: if request.auth != null;
    }
    match /users/{userID}/notifications/{notification} {
      allow read, write: if request.auth != null;
    }
    match /users/{userID}/purchases/{purchase} {
      allow read, write: if request.auth.uid == userID || resource.data.sellerID == request.auth.uid;
    }
    match /users/{userID}/sold/{sold} {
      allow read, write: if request.auth.uid == userID || resource.data.buyerID == request.auth.uid;
    }
    match /tradeOffers/{tradeOfferID} {
      allow read;
      allow write: if request.auth.uid == resource.data.receiverID || request.auth.uid == resource.data.senderID;
      allow create: if request.auth != null;
    }
    match /trades/{tradeID} {
          allow read;
      allow write: if request.auth.uid == resource.data.receiverID || request.auth.uid == resource.data.senderID;
      allow create: if request.auth != null;
    }
    match /trades/{tradeID}/messages/{message} {
      allow read, create: if request.auth != null;
    }
    match /keywords/{keywordID} {
      allow read;
      allow create;
      allow update: if request.resource.data.hits == (resource.data.hits + 1);
    }
    match /medals/{medal} {
        allow read;
    }
    match /alphaFeedback/{alphaFeedbackID} {
        allow write: if request.auth.uid != null;
    }
    match /reports/{reportID} {
        allow write: if request.auth.uid != null;
    }
    match /conversations/{conversationID} {
        allow read, write: if request.auth != null;
    }
    match /conversations/{conversationID}/messages/{messageID} {
        allow read, write: if request.auth != null;
    }
  }
}

Here is the screenshot of the error I get when trying to load in the conversation:

在此处输入图片说明

Here is the error code:

    error - Error [FirebaseError]: Missing or insufficient permissions.
    at new FirestoreError (/Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:410:28)
    at fromRpcStatus (/Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:7519:12)
    at fromWatchChange (/Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:7734:35)
    at PersistentListenStream.onMessage (/Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:15639:27)
    at /Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:15572:30
    at /Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:15608:28
    at /Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:21975:13
    at /Users/lewis/Desktop/www.hoardboard.co.uk/node_modules/@firebase/firestore/dist/index.node.cjs.js:22041:20
    at processTicksAndRejections (internal/process/task_queues.js:95:5) {
  code: 'permission-denied',
  toString: [Function (anonymous)],
  page: '/chat/[conversationid]'

I believe it has something to do with the property of getServerSideProps which will pre-render the page on each request using the data returned by getServerSideProps. Therefore, the token needed by firebase to check if your are indeed logged in won't be loaded by the time the request has been made.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM