如何通过Firestore规则检查数组类型的文档字段是否已包含值?

时间:2020-07-12 21:54:16

标签: javascript firebase google-cloud-firestore firebase-security

给出文档类型:

import React from 'react';
import { compose, withProps } from 'recompose';
import { 
    withScriptjs, 
    withGoogleMap, 
    GoogleMap,
    Marker, 
} from 'react-google-maps';

import icon1 from '../map/icon1.svg';
import iconDead from '../map/iconDead.svg';

const API = 'YOUR_API_KEY';

const MapWithMarkers = compose(
    withProps({
        googleMapURL: `https://maps.googleapis.com/maps/api/js?key=${API}&callbak=initMap`,
        loadingElement: <div style={{ height: `100%` }} />,
        containerElement: <div style={{ height: `800px` }} />,
        mapElement: <div style={{ height: `100%` }} />,
    }),
    withScriptjs,
    withGoogleMap,
)((props) =>
        <GoogleMap
            center={{ lat: 51.510228, lng: -0.132992 }}
            zoom={10}
            defaultOptions={{
                styles: mapStyles
            }}
        >
            {props.markers.map((place, index) => {
                return (
                  <div>
                    <MarkerWithSearch
                        index={place.id}
                        position={{ lat: place.lat, lng: place.lng }} 
                        icon={place.type}  
                        place={place}                
                    />
                  </div>                   
                );
            })}
        </GoogleMap>
);


const MarkerWithSearch = (props) => {
 
    return (
      <div>
      <Marker
          position={props.position}
          icon={ props.icon === "alive" ? 
        ({
          url: icon1,
          scaledSize: new window.google.maps.Size(45, 45)
        }) :
        ({
          url: iconDead,
          scaledSize: new window.google.maps.Size(45, 45)
        })}
      >
      </Marker>
      {/* {console.log(props.position)} */}
      </div>
  )

要执行的约束是允许用户将其interface Post { content: string; sharedBy: Array<string>; } uid数组精确地连接一次。

此外,在我的单元测试中,创建了一个文档,其中sharedBy最初是post.sharedBy。因此,第一次更新成功,并且[]的值变为sharedBy,如以下查询所确认(['1']是测试'1')。

此后,将执行完全相同的更新,但是它不会失败,也可以成功。

给出以下规则:

uid

为什么上面提到的第二次更新成功而不是失败?

编辑

以下是测试文件的内容:

function canShare() {
  return !resource.data.sharedBy.hasAny([request.auth.uid]); // also attempted with `hasAll`
}

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
    match /posts/{postId} {
      allow read: if true;
      allow write: if request.auth != null && canShare();
    }
  }
}

1 个答案:

答案 0 :(得分:1)

我认为安全规则中目前没有任何方法可以强制数组仅包含唯一值。尽管客户端可以使用array-union运算符来确保确实如此,但恶意客户端可以添加重复条目。

确保Firestore中唯一性的唯一方法是确保值是键。因此,您可以将sharedBy制成一个地图,其中的密钥是用户的UID。这样,您可以确保每个UID仅出现一次,因为映射中的键在定义上是唯一的。

另一个选择是将sharedBy元素存储在子集合中,并且在那里也将UID用作文档ID。这样,系统就可以再次确保ID是唯一的。

最后一个选择是仅允许通过Cloud Function或某些其他受信任的过程更新sharedBy数组,您的代码可以在其中强制执行此业务规则。