Firestore如何限制数据模型、防范恶意冗余数据及实现类TypeORM验证?
Firestore数据验证与字段限制方案
一、限制数据仅包含指定字段的最佳方案
针对恶意用户提交多余字段的问题,必须通过多层防护解决,单一方案无法彻底规避风险:
前端过滤(辅助手段,不可单独依赖)
在Angular中,用类配合运行时校验库(如class-validator+class-transformer)处理:- 定义
Person类而非仅TypeScript接口(接口仅编译时有效,运行时会被移除) - 接收用户提交数据后,用
plainToClass方法转换,自动过滤多余字段
示例代码:
import { plainToClass } from 'class-transformer'; class Person { name: string; age: number; } // 处理用户提交的含多余字段的数据 const userData = { name: 'Anna', age: 22, unWantedData: 'Some unwanted data' }; const validPerson = plainToClass(Person, userData, { excludeExtraneousValues: true }); // validPerson 仅保留name和age字段- 定义
Cloud Functions后端校验(核心防护)
前端逻辑可被恶意用户绕过,必须在后端拦截并清洗数据:- 触发写入的云函数中,手动提取允许的字段,丢弃其余数据后再写入Firestore
- 同时校验字段类型的合法性,不符合则直接返回错误
示例代码:
exports.addPerson = functions.https.onCall((data, context) => { // 仅保留允许的字段 const validData = { name: data.name, age: data.age }; // 校验字段类型 if (typeof validData.name !== 'string' || typeof validData.age !== 'number') { throw new functions.https.HttpsError('invalid-argument', '数据格式错误'); } return admin.firestore().collection('people').add(validData); });Firestore安全规则(最后一道防线)
直接在规则中限制文档必须仅包含指定字段,拒绝任何含多余字段的写入请求:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /people/{personId} { allow write: if request.resource.data.keys().hasOnly(['name', 'age']) && request.resource.data.name is string && request.resource.data.age is number; } } }
关于Firestore Converters的适用性
Firestore Converters的核心作用是数据类型转换(如将Firestore Timestamp转为Date、把文档数据转为类实例),它确实能在客户端写入时过滤多余字段,但本质是客户端逻辑——恶意用户可直接调用Firestore API绕过转换器,因此不能单独作为防护手段,仅适合作为前端数据处理的辅助工具。
二、Firestore是否支持类TypeORM的验证器
Firestore没有类似TypeORM的装饰器式验证,但可以通过Firestore安全规则+Cloud Functions实现等效校验逻辑:
1. 通过Firestore安全规则实现基础校验
Firestore规则支持多种校验逻辑,可覆盖TypeORM示例中的大部分场景:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /posts/{postId} { allow write: if // 字段类型校验 request.resource.data.title is string && request.resource.data.rating is number && request.resource.data.email is string && request.resource.data.createDate is timestamp // 标题长度校验 && request.resource.data.title.size() >= 10 && request.resource.data.title.size() <= 20 // 评分范围校验 && request.resource.data.rating >= 0 && request.resource.data.rating <= 10 // 邮箱格式校验(正则表达式) && request.resource.data.email.matches(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/); } } }
2. 通过Cloud Functions实现复杂校验
对于自定义规则、多字段关联校验等复杂需求,可在云函数中使用class-validator库,完全复刻TypeORM的装饰器式校验:
import { IsInt, Min, Max, Length, IsEmail, IsDate, validate } from 'class-validator'; import { plainToClass } from 'class-transformer'; class Post { id?: number; @Length(10, 20) title: string; @IsInt() @Min(0) @Max(10) rating: number; @IsEmail() email: string; @IsDate() createDate: Date; } exports.addPost = functions.https.onCall(async (data, context) => { const post = plainToClass(Post, data); const errors = await validate(post); if (errors.length > 0) { throw new functions.https.HttpsError('invalid-argument', '数据校验失败', errors); } // 校验通过后写入Firestore return admin.firestore().collection('posts').add(post); });
总结
- 基础的格式、范围、字段类型校验,用Firestore安全规则即可实现,性能更高且无需额外代码
- 复杂业务逻辑校验,结合Cloud Functions+
class-validator是更灵活的方案 - 前端校验仅作为补充,用于提升用户体验,不能替代后端和规则的防护
内容的提问来源于stack exchange,提问作者PepeW
相关产品推荐
相关产品推荐

