Firebase 规则:需要一些帮助

问题描述 投票:0回答:1

我正在开发一个项目,在为版主设置权限时遇到困难。尽管添加了一个辅助函数来检查用户是否是主持人,但我的实现似乎没有按预期运行。我已经添加了控制台日志,似乎错误发生在 getModeratorSnippets 处。

这是我的代码的概述:

const onAddRemoveModerator = async (
    user: User,
    communityData: Community,
    isModerator?: boolean
  ) => {
    try {
      setLoadingModeratorMap((prevLoadingMap) => ({
        ...prevLoadingMap,
        [user.uid]: true, // Set loading state to true for the specific user
      }));

      if (!isModerator) {
        // Change the condition here
        // User is not a moderator, add them
        const newSnippet: ModeratorSnippet = {
          communityId: communityData.id,
          isModerator: true,
          userUid: user.uid,
        };

        const batch = writeBatch(firestore);
        batch.set(
          doc(
            firestore,
            `users/${user?.uid}/moderatorSnippets`,
            communityData.id
          ),
          newSnippet
        );
        await batch.commit();

        setCommunityStateValue((prev) => ({
          ...prev,
          moderatorSnippets: [...prev.moderatorSnippets, newSnippet],
        }));

        setIsModerator(true);
      } else {
        // User is already a moderator, remove them
        const batch = writeBatch(firestore);
        batch.delete(
          doc(
            firestore,
            `users/${user?.uid}/moderatorSnippets/${communityData.id}`
          )
        );
        await batch.commit();

        setCommunityStateValue((prev) => ({
          ...prev,
          moderatorSnippets: prev.moderatorSnippets.filter(
            (snippet) =>
              snippet.communityId !== communityData.id ||
              snippet.userUid !== user.uid
          ),
        }));

        setIsModerator(false);
      }

      setLoadingModeratorMap((prevLoadingMap) => ({
        ...prevLoadingMap,
        [user.uid]: false, // Set loading state to false for the specific user
      }));
    } catch (error) {
      console.log("handleAddRemoveModerator error", error);
    }
  };


const fetchModeratorList = async () => {
    setLoadMoreLoading(true);
    const list: User[] = [];
    try {
      let querySnapshot;
      if (searchQuery) {
        const startAtKeyword = searchQuery.toUpperCase();
        const endAtKeyword = searchQuery.toLowerCase() + "\uf8ff";

        const queryRef = query(
          collection(firestore, "users"),
          orderBy("displayName"),
          startAt(startAtKeyword),
          endAt(endAtKeyword)
        );
        querySnapshot = await getDocs(queryRef);
      } else {
        querySnapshot = await getDocs(query(collection(firestore, "users")));
      }

      querySnapshot.forEach((doc) => {
        list.push(doc.data() as User);
      });
      setModeratorList(list);
    } catch (error: any) {
      console.log("error", error);
    }
    setSearchLoading(false);
    setLoadMoreLoading(false);
  };

const getSnippets = async () => {
    setLoading(true);
    try {
      const snippets = await getMySnippets(user?.uid!);
      setCommunityStateValue((prev) => ({
        ...prev,
        mySnippets: snippets as CommunitySnippet[],
        initSnippetsFetched: true,
      }));
      setLoading(false);
    } catch (error: any) {
      console.log("Error getting user snippets", error);
      setError(error.message);
    }
    setLoading(false);
  };

const getModeratorSnippets = async () => {
    setLoading(true);
    try {
      const snippets = await getAllModeratorSnippets();
      setCommunityStateValue((prev) => ({
        ...prev,
        moderatorSnippets: [...snippets], // Replace the existing snippets with the new ones
        initSnippetsFetched: true,
      }));
      setLoading(false);
    } catch (error: any) {
      console.log("Error getting snippets", error);
      setError(error.message);
      setLoading(false);
    }
  };

const getAllModeratorSnippets = async () => {
    const snippetsCollection = collectionGroup(firestore, "moderatorSnippets");
    const snippetsDocs = await getDocs(snippetsCollection);
    const snippets: ModeratorSnippet[] = [];

    snippetsDocs.forEach((doc) => {
      const snippet = doc.data() as ModeratorSnippet;

      if (snippet.isModerator === true) {
        snippets.push({ ...snippet });
      }
    });

    return snippets;
  };

这是我的规则:

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    
    // Allow users to read, write, get, and update their own data
    match /users/{userId}/{restOfPath=**} {
      allow read, write: if request.auth != null;
      
      // Allow moderators to read, write, update, and get
      match /moderatorSnippets/{communityId} {
        allow read, write: if isModerator(userId, communityId);
      }
      
    }
  
  // Helper function to check if the user is a moderator
  function isModerator(userId, communityId) {
    return request.auth != null &&
           exists(/databases/(database)/documents/users/$(userId)/moderatorSnippets/$(communityId));
  }
  
}

我尝试实现一个辅助函数(isModerator),以在授予 moderatorSnippets 读写权限之前检查用户是否是版主。然而,它似乎并没有达到预期的效果。

javascript google-cloud-firestore firebase-security web-development-server
1个回答
0
投票

您似乎错过了 Firebase 文档中的一个重要部分,其中解释了规则不是过滤器。这些规则本身不会过滤数据,而只是确保您的代码仅请求它有权访问的数据。

由于您的代码请求来自

moderatorSnippets
的所有文档,并且您已将规则设置为不允许这样做,因此规则引擎会拒绝该读取操作。


正确的设置是确保您的代码仅请求根据您的规则允许的文档。因此,您必须编写查询以符合规则。

我不确定这对于您当前的数据模型是否可行,因为查询只能对它返回的文档中存在的信息进行过滤/排序,并且您的规则似乎会检查另一个文档是否存在(

exists(/databases/(database)/documents/users/$(userId)/moderatorSnippets/$(communityId))
).

如果这确实是一个单独的文档,您将需要复制您正在查询的

moderatorSnippets
中的信息,以便您可以在那里进行过滤 - 然后通过您的规则保护 that

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.