Flutter Firebase规则管理插件firebase_rules的使用

Flutter Firebase规则管理插件firebase_rules的使用

firebase_rules 是一个类型安全的Firebase规则生成器,适用于Firestore、Storage和Realtime Database。它提供了一种在Dart中定义Firebase规则的方法,并通过代码补全和自定义lint规则来确保规则的质量。

功能特性

  • 类型安全:为Firestore、Storage和Realtime Database创建规则时提供类型安全的环境。
  • 自定义Lint规则:在部署前捕捉问题。
  • 语法相似性:模仿Firebase规则语法,便于迁移。
  • 易读性和维护性:规则更易于阅读和维护,并且可以在Realtime Database规则中添加注释。

限制

  • Realtime Database规则不是真正类型的,但提供了代码补全的好处。

安装

为了防止潜在的问题,建议在一个专门的项目中创建规则。以下是安装步骤:

pubspec.yaml

dependencies:
  firebase_rules: latest
  # 如果你正在使用来自 `cloud_firestore_platform_interface` 的类型
  firebase_rules_convert: latest

dev_dependencies:
  build_runner: latest
  firebase_rules_generator: latest

  # 使用 `firebase_rules_linter`
  custom_lint: latest
  firebase_rules_linter: latest

analysis_options.yaml

# 使用 `firebase_rules_linter`
analyzer:
  plugins:
    - custom_lint

使用指南

注解

所有规则的起点是注解。Firestore、Storage和Database规则应分别定义在不同的文件中以避免冲突。

import 'package:firebase_rules/database.dart';
import 'package:firebase_rules/firebase.dart';

/// 创建Firestore规则
@FirebaseRules(service: Service.firestore)
final firestoreRules = [];

/// 创建Storage规则
@FirebaseRules(service: Service.storage)
final storageRules = [];

/// 创建Realtime Database规则
@DatabaseRules()
final databaseRules = [];

匹配规则(Matches)

现在可以开始定义匹配语句。

import 'package:firebase_rules/firebase.dart';
import 'shared.dart';

@FirebaseRules(service: Service.firestore)
final firestoreRules = [
  Match<FirestoreResource>(
    firestoreRoot,
    matches: (database, request, resource) => [
      Match<FirestoreResource<User>>(
        '/users/{userId}',
        rules: (userId, request, resource) => [],
      ),
      Match<FirestoreResource>(
        '/other/stuff',
        rules: (_, request, resource) => [],
      ),
    ],
  ),
];

@FirebaseRules(service: Service.storage)
final storageRules = [
  Match<StorageResource>(
    storageRoot,
    matches: (bucket, request, resource) => [
      Match<StorageResource>(
        '/images/{imageId}',
      ),
    ],
  ),
];

规则定义(Rules)

规则是核心部分。

import 'package:firebase_rules/firebase.dart';
import 'shared.dart';

@FirebaseRules(service: Service.firestore)
final firestoreRules = [
  Match<FirestoreResource>(
    firestoreRoot,
    matches: (database, request, resource) => [
      Match<FirestoreResource<User>>(
        '/users/{userId}',
        rules: (userId, request, resource) => [
          Allow([Operation.read], resource.data.userId.rules() == userId),
        ],
      ),
    ],
  ),
];

规则语言

该包包含了一个用Dart重新实现的Firebase规则语言。这些调用将由生成器转换为正确的Firebase规则语法。

import 'package:firebase_rules/firebase.dart';

void example() {
  ''.rules().range(0, 1);
  [].rules<RulesString>().concat([].rules());
  rules.string(true);
  rules.raw<bool>("foo.bar.baz == 'qux'");
}

函数

顶级函数可以用作规则函数。

import 'package:firebase_rules/firebase.dart';

bool isSignedIn() {
  return request.auth?.uid != null;
}

@FirebaseRules(
  service: Service.firestore,
  functions: [isSignedIn],
)
final rules = [
  Match<FirestoreResource>(firestoreRoot),
];

组织

匹配语句的任何函数参数都可以拆分以进行组织。

import 'package:firebase_rules/firebase.dart';
import 'shared.dart';

List<Match> detached(
  RulesString database,
  RulesRequest<FirestoreResource> request,
  FirestoreResource resource,
) =>
    [
      Match<FirestoreResource<User>>(
        '/users/{userId}',
        rules: (userId, request, resource) => [
          Allow([Operation.read], resource.data.userId.rules() == userId),
        ],
      ),
    ];

@FirebaseRules(service: Service.firestore)
final firestoreRules = [
  Match<FirestoreResource>(firestoreRoot, matches: detached),
];

枚举

枚举可以通过生成器替换为原始字符串。

import 'package:firebase_rules/firebase.dart';

@FirebaseRules(
  service: Service.firestore,
  enums: [Test.map],
)
final firestoreRules = [
  Match<FirestoreResource>(
    firestoreRoot,
    matches: (database, request, resource) => [
      Match<FirestoreResource<TestResource>>(
        '/test',
        rules: (_, request, resource) => [
          Allow([Operation.read], resource.data.test == Test.a),
        ],
      ),
    ],
  ),
];

enum Test { a, b, c }

abstract class TestResource {
  Test get test;
}

生成规则

最后,可以运行生成器。

$ dart pub run build_runner build

对于每个rules.dart文件,这将在同一目录下生成一个rules.rules文件。将你的Firebase配置指向这个文件以使用规则。

Realtime Database规则

数据库规则与Firestore和Storage规则类似,但有一些不同之处:

  • 第一个匹配必须以rules开头,这是数据库的根。
  • 通配符用$表示。
import 'package:firebase_rules/database.dart';

@DatabaseRules()
final databaseRules = [
  Match(
    r'rules/users/$userId',
    read: (userId) => auth != null && auth?.uid == userId,
    write: (userId) => userId == 'user1'.rules(),
    validate: (userId) => !data.exists(),
    indexOn: ['uid', 'email'],
    matches: (userId) => [
      Match(
        r'contracts/$contractId',
        read: (contractId) =>
            root.child('users'.rules()).child(userId).child(contractId).val<int?>() != null,
        write: (contractId) =>
            root.child('users'.rules()).child(userId).child(contractId).val() != null,
      ),
    ],
  ),
];

示例代码

以下是一个完整的示例,展示了如何使用firebase_rules定义Firestore规则。

import 'package:firebase_rules/firebase.dart';
import 'package:cloud_firestore_platform_interface/cloud_firestore_platform_interface.dart';

bool isSignedIn(RulesRequest request) => request.auth != null;

bool isOwner(RulesRequest request, RulesString uid) {
  final requestingUid = request.auth?.uid;
  return requestingUid == uid;
}

@FirebaseRules(
  service: Service.firestore,
  functions: [isSignedIn, isOwner],
)
final firestoreRules = [
  Match<FirestoreResource>(
    firestoreRoot,
    rules: (database, request, resource) => [
      Allow([Operation.read], request.auth?.uid == 'god'.rules()),
    ],
    matches: (database, request, resource) => [
      Match<FirestoreResource<User>>(
        '/users/{userId}',
        rules: (userId, request, resource) => [
          Allow([Operation.read], isSignedIn(request)),
          Allow([Operation.create, Operation.update], isOwner(request, userId)),
        ],
      ),
      Match<FirestoreResource<Content>>(
        '/content/{contentId}',
        rules: (contentId, request, resource) => [
          Allow([Operation.read], isSignedIn(request) && resource.data.public),
          Allow(
            [Operation.write],
            rules.firestore.get<User>(rules.path('/users/${request.auth?.uid}'.rules())).data.contentIds.rules<RulesString>().contains(contentId) &&
                rules.firestore.exists(rules.path('/users/${request.auth?.uid}'.rules(), database: 'default')),
          ),
        ],
      ),
    ],
  ),
];

abstract class User {
  List<String> get contentIds;
  Blob get profileImage;
}

abstract class Content {
  bool get public;
}

希望以上内容能帮助你更好地理解和使用firebase_rules插件。如果有任何问题或需要进一步的帮助,请随时提问!


更多关于Flutter Firebase规则管理插件firebase_rules的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Firebase规则管理插件firebase_rules的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter项目中,管理Firebase实时数据库或Firestore的安全规则可以通过firebase_rules插件来实现自动化和版本控制。虽然firebase_rules插件本身并不直接提供命令行工具来部署规则,但它可以帮助你在项目中管理这些规则文件,并通过CI/CD流程部署它们。

以下是如何在Flutter项目中设置和使用firebase_rules插件来管理Firebase安全规则的一个基本示例。

1. 安装firebase_rules插件

首先,确保你的Flutter项目已经初始化,并且位于项目根目录下。然后,在pubspec.yaml文件中添加firebase_rules依赖:

dependencies:
  flutter:
    sdk: flutter
  # 其他依赖...

dev_dependencies:
  firebase_rules: ^x.y.z  # 替换为最新版本号

运行flutter pub get来安装依赖。

2. 创建Firebase规则文件

在你的Flutter项目根目录下,创建一个名为firebase.rules的文件,并在其中编写你的Firebase安全规则。例如,对于Firestore:

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

3. 配置firebase_rules插件

pubspec.yaml文件中,配置firebase_rules插件以指向你的规则文件:

firebase_rules:
  rules: firebase.rules

4. 部署规则(手动或使用CI/CD)

虽然firebase_rules插件本身不直接提供部署功能,但你可以使用Firebase CLI来部署这些规则。首先,确保你已经安装了Firebase CLI,并且已经通过firebase login命令登录。

然后,在命令行中导航到你的Flutter项目根目录,并运行以下命令来初始化Firebase项目(如果尚未初始化):

firebase init

按照提示选择你的项目和其他配置选项。之后,你可以使用以下命令来部署Firebase规则:

firebase deploy --only firestore:rules

或者,如果你使用的是实时数据库:

firebase deploy --only database:rules

5. 自动化部署(可选)

为了自动化部署过程,你可以将上述部署命令集成到你的CI/CD管道中。例如,在GitHub Actions中,你可以创建一个工作流文件(.github/workflows/deploy-firebase-rules.yml),并在其中添加如下步骤:

name: Deploy Firebase Rules

on:
  push:
    paths:
      - 'firebase.rules'

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v2
      
      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '14'
      
      - name: Install Firebase CLI
        run: npm install -g firebase-tools
      
      - name: Login to Firebase
        run: firebase login --no-localhost
        env:
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
      
      - name: Use Firebase CLI to deploy rules
        run: firebase deploy --only firestore:rules

注意:在上面的GitHub Actions示例中,你需要创建一个名为FIREBASE_TOKEN的仓库秘密,该秘密包含你的Firebase CLI登录令牌。你可以通过运行firebase login:ci命令来获取这个令牌。

通过以上步骤,你就可以在Flutter项目中有效地管理和部署Firebase安全规则了。

回到顶部