Flutter云功能集成插件cloud_frog的使用

Flutter云功能集成插件cloud_frog的使用

Cloud Frog

Cloud Frog 是一个库,用于帮助使用 Dart Frog 构建安全的 Google Cloud 服务。

Dart Frog 是一个简单易用的框架,用于在 Dart 中创建服务器并将其部署到 Google Cloud Run(以及其他环境)。在这种情况下,Cloud Frog 提供了额外的支持,以便更细粒度地实现这些服务的身份验证和授权。

Cloud Frog 的另一个目标是在未来支持由 Dart Frog 支持的其他环境。

特性

目前,Cloud Frog 在两个不同的场景下提供了路由级别的访问控制:

  1. 服务到服务身份验证
  2. 使用 Firebase 的最终用户身份验证

服务到服务身份验证

服务到服务身份验证由 Cloud Frog 以 Dart Frog 中间件的形式提供,可以在路由级别限制对某些 Cloud IAM 服务帐户的服务调用。

虽然 Google Cloud Run 可以通过 IAM 实现 HTTPS 的访问控制(参见Google Cloud Run 文档),但在某些情况下,在自己的服务代码中实现这种验证可能更为方便。这些情况包括当您的服务具有公共和私有路由组合时,或者不同的服务帐户应该有权访问不同的路由时。

请注意,无论何时在 Google Cloud Run 和 IAM 中配置访问控制时,传入的请求会在执行您的服务代码之前进行验证。尽管从技术上讲,可以将 Google Cloud IAM 和 Cloud Frog 访问控制结合起来,但这并没有多大好处,并且可能会增加复杂性。

如果您选择坚持使用 Google Cloud IAM,配置访问控制归结为以下步骤:

  • 将服务的SECURITY/Authentication设置为Require authentication
  • 在服务的PERMISSIONS面板中添加服务帐户(点击ADD PRINCIPAL按钮)并授予Cloud Run Invoker角色。

如果您决定使用 Cloud Frog 身份验证控制,继续阅读!请注意,在这两种情况下,请求都使用相同的底层机制进行身份验证:OIDC(OpenID Connect)令牌。

Cloud Frog 建立在 Dart Frog 的身份验证支持之上,通过解析和验证包含在Authorization头中的 OIDC 令牌(使用Bearer方案)来实现这一点。如果令牌有效并且帐户被授权,则执行其余的路由处理程序。如果不是这种情况,则返回 HTTP 状态码 401(未授权 - 缺失或无效令牌)或 403(禁止 - 有效令牌但错误的用户)。

最终用户身份验证使用 Firebase

使用 Firebase 的最终用户身份验证也由 Cloud Frog 以 Dart Frog 中间件的形式提供,可以在特定路由中提取已登录的 Firebase 用户。

与服务到服务场景不同,此中间件不处理限制特定用户的访问,但它确保请求经过身份验证,并将提取的用户信息放入请求上下文中以进一步使用。

类似于服务到服务场景,此中间件使用 OIDC(OpenID Connect)令牌,这些令牌由 Firebase Auth 发行。

入门指南

前提条件

如果您还没有服务器,请遵循Dart Frog 快速入门来设置一个服务器。

您还需要有一个 Google Cloud 项目,您的服务将在其中部署。在该项目中,在 IAM & Admin 部分创建一个服务帐户,并确保授予其Cloud Run Invoker角色。

最后,安装gcloud CLI,这将是部署服务所需的。

导入 Cloud Frog

将 Cloud Frog 作为依赖项添加到项目的pubspec.yaml文件中。

dependencies:
  cloud_frog: ^1.1.0

运行pub get来获取cloud_frog

添加 Cloud Frog 中间件

Dart Frog 中间件是在给定路由的请求处理逻辑中执行的函数。中间件可以添加到顶级路由或单独的子路由。添加到顶级路由的中间件将为所有路由执行。

服务到服务身份验证

为了认证给定路由的服务到服务请求,将 Cloud Frog 中间件添加到_middleware.dart文件:

import 'dart:io';

import 'package:cloud_frog/cloud_frog.dart';
import 'package:dart_frog/dart_frog.dart';

Handler middleware(Handler handler) => handler
    .use(verifyServiceAccount(
        ['my-service-account@my-project-123456.iam.gserviceaccount.com'],
        issuer: issuerGoogle,
    ));

在上述文件中,verifyServiceAccount中间件配置了一个允许执行路由(或路由列表)的单个服务帐户(my-service-account@my-project.iam.gserviceaccount.com)。issuer参数确保验证令牌的发行人字段为 Google 帐户。

最终用户身份验证使用 Firebase

同样,为了认证给定路由的 Firebase 最终用户请求,将 Cloud Frog 中间件添加到_middleware.dart文件:

import 'dart:io';

import 'package:cloud_frog/cloud_frog.dart';
import 'package:dart_frog/dart_frog.dart';

Handler middleware(Handler handler) => handler
    .use(authenticateFirebaseUser);

在上述文件中,authenticateFirebaseUser中间件将确保该路由的请求经过 Firebase 用户的身份验证。对于每个请求,在完成此验证后,相应的User对象将被放置在请求上下文中以进一步使用。

请求处理程序实现可以通过请求上下文访问User对象,用于授权和/或个性化逻辑目的:

const allowedEmails = [...];

Response onRequest(RequestContext context) {
  final user = context.read<User>();
  if (!user.emailVerified || !allowedEmails.contains(user.email)) {
    return Response(statusCode: HttpStatus.forbidden);
  }

  // 在这里使用用户

  return Response(body: '欢迎 ${user.email}');
}

用户授权可以改用下游中间件处理,使用您自己的实现或内置的verifyContextUser中间件:

const allowedEmails = [...];

Handler middleware(Handler handler) {
  return handler
      .use(
        verifyContextUser(allowedEmails),
      )
      .use(
        authenticateFirebaseUser,
      );
}

部署服务

遵循Dart Frog 部署指南将您的服务部署到 Google Cloud。

请注意,--allow-unauthenticated选项在gcloud命令中指示 Cloud Run 允许任何请求。这意味着身份验证和授权将完全由您在路由中设置的中间件处理。

使用

通过调用verifyServiceAccount函数配置并包含 Cloud Frog 中间件:

import 'dart:io';

import 'package:cloud_frog/cloud_frog.dart';
import 'package:dart_frog/dart_frog.dart';

Handler middleware(Handler handler) => handler
    .use(verifyServiceAccount(
        [
            'my-service-account@my-project-123456.iam.gserviceaccount.com',
            'my-service-account@my-other-project-987654.iam.gserviceaccount.com',
        ],
        verifyAudience: true,
        issuer: issuerGoogle,
    ));

第一个参数是一组允许访问当前路由的服务帐户。这些服务帐户不需要有任何特定的角色(如果您仍在使用 Google Cloud IAM 访问控制,它们需要拥有Cloud Run Invoker角色)。 请注意,这些帐户不一定需要注册在您的服务部署的同一项目中。从服务的角度来看,它们只是与令牌发行人关联的电子邮件地址(更多关于发行人的信息见下文)。

命名参数verifyAudience表示是否应验证令牌的aud字段。Cloud Frog 目前仅支持验证受众对应于请求 URI。此参数是可选的,默认值为true

命名参数issuer表示 OIDC 令牌的发行人。它是可选的,如果没有指定,则不会执行验证。Cloud Frog 提供了issuerGoogle常量,代表 Google 帐户(https://accounts.google.com)。

日志记录

Cloud Frog 中间件可以选择性地配置日志记录器。如果中间件可以从路由的Context中找到dart_frog_request_logger包中的RequestLogger实例,则它将使用该日志记录器并记录可能有助于验证服务帐户的消息。

为了让日志记录器对 Cloud Frog 中间件可用,将其作为依赖项添加到路由的中间件中:

import 'dart:io';

import 'package:cloud_frog/cloud_frog.dart';
import 'package:dart_frog/dart_frog.dart';
import 'package:dart_frog_request_logger/dart_frog_request_logger.dart';
import 'package:dart_frog_request_logger/log_formatters.dart';

Handler middleware(Handler handler) => handler
    .use(
        verifyServiceAccount(
            [
                'my-service-account@my-project-123456.iam.gserviceaccount.com',
                'my-service-account@my-other-project-987654.iam.gserviceaccount.com',
            ],
            verifyAudience: true,
            issuer: issuerGoogle,
        ),
    )
    .use(
      provider<Future<RequestLogger>>(
        (context) async => RequestLogger(
          headers: context.request.headers,
          logFormatter: formatCloudLoggingLog(projectId: await projectId),
        ),
      ),
    );

请注意,提供Future<RequestLogger>而不是RequestLogger。这是因为在构造函数中使用的projectId getter(感谢 Cloud Frog)是异步的。如果 Google Cloud 项目 ID 是硬编码的,则可以直接返回RequestLogger实例:

    .use(
        provider<RequestLogger>(
            (context) => RequestLogger(
                headers: context.request.headers,
                logFormatter: formatCloudLoggingLog(projectId: 'my-project-123456'),
            ),
        ),
    )

更多关于Flutter云功能集成插件cloud_frog的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter云功能集成插件cloud_frog的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


cloud_frog 是一个用于 Flutter 的插件,旨在简化与云函数的集成。通过 cloud_frog,开发者可以轻松地在 Flutter 应用中调用云函数,处理异步任务,并获取返回结果。以下是如何使用 cloud_frog 插件的详细步骤:

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 cloud_frog 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  cloud_frog: ^0.1.0  # 请使用最新版本

然后,运行 flutter pub get 来获取依赖。

2. 初始化插件

在 Flutter 应用中,你需要在 main.dart 或其他入口文件中初始化 cloud_frog 插件。

import 'package:cloud_frog/cloud_frog.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // 初始化 CloudFrog
  await CloudFrog.initialize(
    apiKey: 'YOUR_API_KEY',  // 你的云函数平台API密钥
    projectId: 'YOUR_PROJECT_ID',  // 你的云函数项目ID
  );
  
  runApp(MyApp());
}

3. 调用云函数

在 Flutter 应用中,你可以使用 CloudFrog.callFunction 方法来调用云函数。

import 'package:flutter/material.dart';
import 'package:cloud_frog/cloud_frog.dart';

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('CloudFrog Example'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              try {
                // 调用云函数
                final response = await CloudFrog.callFunction(
                  functionName: 'your_function_name',  // 云函数名称
                  data: {'param1': 'value1', 'param2': 'value2'},  // 传递给云函数的参数
                );
                
                // 处理返回结果
                print('Response: ${response.data}');
              } catch (e) {
                print('Error: $e');
              }
            },
            child: Text('Call Cloud Function'),
          ),
        ),
      ),
    );
  }
}

4. 处理返回结果

CloudFrog.callFunction 方法返回一个 CloudFunctionResponse 对象,你可以通过 response.data 获取云函数返回的数据。

final response = await CloudFrog.callFunction(
  functionName: 'your_function_name',
  data: {'param1': 'value1', 'param2': 'value2'},
);

// 处理返回结果
print('Response: ${response.data}');

5. 错误处理

在调用云函数时,可能会遇到各种错误,例如网络问题、云函数执行失败等。你可以使用 try-catch 块来捕获并处理这些错误。

try {
  final response = await CloudFrog.callFunction(
    functionName: 'your_function_name',
    data: {'param1': 'value1', 'param2': 'value2'},
  );
  print('Response: ${response.data}');
} catch (e) {
  print('Error: $e');
}

6. 高级配置

cloud_frog 还支持一些高级配置,例如设置超时时间、自定义请求头等。你可以在 CloudFrog.initialize 方法中进行配置。

await CloudFrog.initialize(
  apiKey: 'YOUR_API_KEY',
  projectId: 'YOUR_PROJECT_ID',
  timeout: Duration(seconds: 30),  // 设置请求超时时间
  headers: {'Custom-Header': 'value'},  // 自定义请求头
);

7. 注销插件

在你的应用生命周期结束时,可以调用 CloudFrog.dispose 方法来释放资源。

[@override](/user/override)
void dispose() {
  CloudFrog.dispose();
  super.dispose();
}
回到顶部