flownative/google-cloudstorage

此Flow包允许您在Google Cloud Storage中存储资产(资源)并将资源发布到GCS。

v6.0.0-beta.4 2024-01-18 08:50 UTC

README

MIT license Packagist Packagist Maintenance level: Love

Neos和Flow的Google Cloud Storage适配器

Flow包允许您将资产(资源)存储在Google Cloud Storage中并将资源发布到GCS。由于Neos CMS在底层使用Flow的资源管理,此适配器也适用于Neos中的所有类型的资产。

主要功能

  • 在私有GCS存储桶中存储所有资产或特定集合
  • 将资产发布到私有或公共GCS存储桶
  • 支持选择媒体类型的GZIP压缩
  • 提供命令行界面以执行连接检查、清空GCS存储桶或一致性检查并清理等任务

使用此连接器,您可以在不存储任何资产(图像、PDF等)的本地Web服务器上运行Neos网站。

安装

Flownative Google Cloud Storage连接器通过Composer以常规Flow包的形式安装。只需将flownative/google-cloudstorage包含到您的Flow或Neos分布的依赖项中即可。

$ composer require flownative/google-cloudstorage

配置

为了与Google API通信,您需要提供一个账户的凭据,该账户有权访问GCS(有关设置服务用户的说明,请参阅下一节)。将以下配置添加到您所需Flow上下文的Settings.yaml(例如在Configuration/Production/Settings.yaml)中,并确保用您的数据替换私有密钥

Flownative:
  Google:
    CloudStorage:
      profiles:
        default:
          credentials:
            privateKeyJsonPathAndFilename: 'Data/Secrets/MyGoogleProject-abc123457def.json'

除了使用文件外,私有密钥还可以直接指定为base64编码的字符串。这允许通过环境变量提供私有密钥

Flownative:
  Google:
    CloudStorage:
      profiles:
        default:
          credentials:
            privateKeyJsonBase64Encoded: '%env:SOME_ENVIRONMENT_VARIABLE_WITH_PRIVATE_KEY%'

您可以通过使用选择的存储桶执行connect命令来测试您的设置。

$ ./flow gcs:connect storage.example.net

目前,您只能定义一个连接配置文件,即“默认”配置文件。未来版本可能支持其他配置文件。

存储桶权限、服务账户和密钥

公开访问

为了让存储桶可供互联网上每个人读取(用于交付资产),请按照以下步骤操作

  1. 在Google Cloud控制台中,转到云存储浏览器页面。
  2. 在存储桶列表中,单击您要公开的存储桶名称。
  3. 在页面顶部附近选择权限选项卡。
  4. 单击添加按钮。
  5. 出现添加主体对话框。
  6. 新主体字段中,输入allUsers
  7. 选择角色下拉菜单中,选择云存储子菜单,然后单击存储对象查看器选项。注意:这包括列出存储桶中对象的权限。如果您不想公开列出,请使用存储旧版对象读取器代替。
  8. 单击保存
  9. 单击允许公开访问

这处理了“读取端”的事务。

服务账户设置

为了使Flow能够管理资产,您需要设置一个具有所需权限的服务账户。

  1. 在Google Cloud控制台中,转到服务账户页面。
  2. 在服务账户列表中,点击 + 创建服务账户
  3. 填写一个名称,调整生成的 服务账户 ID,添加描述
  4. 点击 创建并继续
  5. 现在将 存储对象管理员 角色授予用户
  6. 点击 继续
  7. 点击 完成

密钥生成

为了对服务账户进行身份验证,您需要一个服务账户密钥。

  1. 转到服务账户详情页面
  2. 选择页面顶部的 密钥 选项卡。
  3. 点击 添加密钥 按钮,选择 创建新密钥
  4. 选择 JSON 作为密钥类型
  5. 私钥文件将被下载 - 请妥善保管!如果丢失,必须生成新的密钥。

密钥文件现在可以使用 privateKeyJsonPathAndFilename 选项或作为上述描述中的 base64 编码字符串用于 privateKeyJsonBase64Encoded

将资产发布到 Google 云存储

一旦配置了连接器包,您就可以添加一个新的发布目标,该目标使用该连接并将此目标分配给您的集合。

Neos:
  Flow:
    resource:
      collections:
        persistent:
          target: 'googlePersistentResourcesTarget'
      targets:
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            bucket: 'target.example.net'
            keyPrefix: '/'
            baseUri: 'http://storage.googleapis.com/target.example.net/'

由于新的发布目标最初将是空的,您需要使用 resource:publish 命令将您的资产发布到新目标。

$ ./flow resource:publish

此命令将上传您的文件到目标,并从现在开始使用计算出的远程 URL 对所有您的资产进行操作。

切换集合的存储

如果您想从默认的本地文件系统存储迁移到远程存储,您需要将所有现有的持久资源复制到新的存储,并之后默认使用该存储。

您首先通过将 GCS 连接器添加到您的配置中,添加一个新的存储。由于您可能还想通过远程存储系统提供服务,您还添加了一个包含您的已发布资源的目标。

Neos:
  Flow:
    resource:
      storages:
        googlePersistentResourcesStorage:
          storage: 'Flownative\Google\CloudStorage\GcsStorage'
          storageOptions:
            bucket: 'storage.example.net'
            keyPrefix: '/'
      targets:
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            bucket: 'target.example.net'
            keyPrefix: '/'
            baseUri: 'http://storage.googleapis.com/target.example.net/'

关于配置选项的一些说明

keyPrefix 选项允许您在多个网站或应用程序之间共享一个存储桶。所有对象键都将由给定的字符串前缀。

baseUri 选项定义了指向您的已发布资源的公开可访问地址的根。在上面的示例中,baseUri 指向一个需要单独设置的子域。如果 baseUri 为空,Google 云存储发布目标将自动确定公共 URL。

为了将资源复制到新的存储,我们需要一个使用存储和新发布目标临时的集合。

Neos:
  Flow:
    resource:
      collections:
        tmpNewCollection:
          storage: 'googlePersistentResourcesStorage'
          target: 'googlePersistentResourcesTarget'

现在您可以使用 resource:copy 命令(在 Flow 3.1 或 Neos 2.1 及更高版本中可用)

$ ./flow resource:copy persistent tmpNewCollection --publish

这将从您当前的存储(本地文件系统)复制所有文件到新的远程存储。 --publish 标志表示此命令还将所有资源发布到新目标,您在当前存储和发布目标上的状态与在新目标上相同。

现在您可以覆盖旧集合配置并删除临时配置

Neos:
  Flow:
    resource:
      collections:
        persistent:
          storage: 'googlePersistentResourcesStorage'
          target: 'googlePersistentResourcesTarget'

清除缓存,完成。

$ ./flow flow:cache:flush

单存储桶或双存储桶设置

您可以为存储和目标分别创建单独的存储桶,或者使用相同的存储桶作为存储和目标。

单存储桶

在单存储桶设置中,相同的存储桶将被用作存储和目标。所有资源都是公开可访问的,因此 Flow 可以在资源上传后立即渲染指向资源的 URL。

此设置速度快且节省存储空间,因为资源不需要复制,只需存储一次。在后台,URL 有点难看,因为它们只由域名和资源的 SHA1 组成。

https://storage.googleapis.com/bucket.example.com/a865defc2a48f060f15c3f4f21f2f1e78f154789

双存储桶

在双桶配置中,资源将被重复:原始资源存储在“存储”桶中,然后复制到“目标”桶。每次创建或导入新资源时,它将存储在存储桶中,然后自动发布(即复制)到目标桶。

您可以选择这种配置,以便有面向人和SEO友好的URL指向您的资源,因为复制到目标桶的对象可以有更具说明性的名称,该名称包含资源的原始文件名(有关publicPersistentResourceUris选项的详细信息,请见下文)。

自定义公共URL

Google Cloud Storage目标支持自定义向用户展示的URL的方式。尽管用于桶中对象的路径和文件名相对固定(有关baseUrikeyPrefix选项,请参见上文),您可能希望使用反向代理或内容分发网络来交付存储在您的目标桶中的资源。在这种情况下,您可以指示目标根据您自己的规则生成URL。确保这些URL实际可用是您的责任。

假设我们已经设置了一个充当反向代理的Web服务器。对assets.flownative.com的请求被重写,以便使用类似https://assets.flownative.com/a817…cb1/logo.svg的URI实际上会交付存储在存储桶中并使用给定SHA1的文件。

您可以通过定义包含占位符的模式来告诉目标生成这样的URI

      targets:
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            bucket: 'flownativecom.flownative.cloud'
            baseUri: 'https://assets.flownative.com/'
            persistentResourceUris:
              pattern: '{baseUri}{sha1}/{filename}'

可能的占位符有

  • {baseUri} 在目标选项中定义的基本URI
  • {bucketName} 目标的桶名称
  • {keyPrefix} 目标配置的关键前缀
  • {sha1} 资源的SHA1
  • {filename} 资源的全名,例如 "logo.svg"
  • {fileExtension} 资源的文件扩展名,例如 "svg"

出于传统和便利的原因,默认模式取决于所使用的设置

  • 未设置模式和baseUri: https://storage.googleapis.com/{bucketName}/{keyPrefix}{sha1}
  • 未设置模式: {baseUri}/{keyPrefix}{sha1}/{filename}

目标将自动检测相应的设置并相应设置模式。当然,您可以像上面解释的那样指定pattern设置来覆盖模式。

动态自定义基本URI

您的应用程序可以负责通过注册自定义方法来渲染基本URI。在设置选项后,目标将调用您的方 法,并使用返回的字符串作为基本URI。

此机制允许您根据当前请求调整域名或其他基本URI的部分。在以下示例中,我们使用客户基本URI方法将域名 "example.com" 替换为 "replaced.com"。

namespace Flownative\Test;

class CloudStorageDemo {
    /**
     * @param array $targetOptions
     * @return string
     */
    public function renderBaseUri(array $targetOptions): string
    {
        return str_replace('example.com', 'replaced.com', $targetOptions['baseUri']);
    }
}
      targets:
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            customBaseUriMethod:
              objectName: 'Flownative\Test\CloudStorageDemo'
              methodName: 'renderBaseUri'

以下选项传递给您的渲染方法

  • targetClass
  • bucketName
  • keyPrefix
  • baseUri
  • persistentResourceUriEnableSigning

发布有限寿命的URI

您可以通过创建私有Google Cloud Storage桶来保护对资源的访问。例如,您可以声明一个桶策略,该策略仅授予您的应用程序拥有的服务密钥访问权限。

假设您生成作为PDF文件的发票,并希望将它们安全地存储在私有桶中。在某个时候,您将希望允许授权客户下载发票。实现此功能的最简单方法是生成一个特殊的签名链接,该链接允许在一定时间内访问给定的资源。

Google Cloud Storage 目标可以处理对持久资源的签名链接。只需启用签名并指定签名有效期(以秒为单位),如下所示示例。但请注意,任何拥有此类生成的链接的人都可以在链接有效期间下载受保护的资源。

      targets:
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            bucket: 'flownativecom.flownative.cloud'
            baseUri: 'https://assets.flownative.com/'
            persistentResourceUris:
              pattern: '{baseUri}{sha1}/{filename}'
              enableSigning: true
              signatureLifetime: 600

此配置下生成的链接将如下所示

https://assets.flownative.com/d19409d1315d0cf268c191f33d5a3c6cde29f903/photo.jpg?GoogleAccessId=robert@my-project.iam.gserviceaccount.com&Expires=1568877386&Signature=VCyYVsyxScRf6VkQ88g16haWKewlZ4iVYOAio9HcGjT8VmhwNh8OG1zYSE%2BoC8TDpLNEPrmbSkRY92Tj4pntfLP5psV4Q%2BBakmh66crQHidb0%2BW2wkKI2GKm9CX%2FCF6kRdtObdYF1oxj1c6Fz3F31txylCilPMjL%2Fq0%2BWtvwk1hczv7vTccHuOgP5ymAUV5Z%2FlKSn7lQMb9BduUrCartzJZOUbUrrdlUHDle80cziWrxoDJSDy3dAM89Dhe9g5rmJ6xsN4YF%2BZSo1xzCW2NMdghSzlz5yBhZAIf6nhO9VjVzuuF1X70X00pNU19FQJiYPxC3VD7UhggZ2%2B3KWoAsRg%3D%3D

gzip 压缩

Google Cloud Storage 支持gzip压缩以向用户交付文件,但这些文件需要在Google Cloud Storage外部压缩,然后作为gzip压缩数据上传。此插件支持在资源发布时实时转码。Google Cloud Storage 存储中的数据始终以未压缩的形式存储。配置为gzip压缩的媒体类型之一的文件在发布到Google Cloud Storage 目标时将自动转换为gzip格式。

您可以为压缩级别和应如此压缩的媒体类型进行配置

Neos:
  Flow:
    resource:
      targets:
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            gzipCompressionLevel: 9
            gzipCompressionMediaTypes:
            - 'text/plain'
            - 'text/css'
            - 'text/xml'
            - 'text/mathml'
            - 'text/javascript'
            - 'application/x-javascript'
            - 'application/xml'
            - 'application/rss+xml'
            - 'application/atom+xml'
            - 'application/javascript'
            - 'application/json'
            - 'application/x-font-woff'
            - 'image/svg+xml'

请注意,为已压缩的数据添加媒体类型(例如图片或电影)可能会增加数据大小,因此应避免这样做。

Google Cloud Storage (GCS) 的完整示例配置

Neos:
  Flow:
    resource:
      storages:
        googlePersistentResourcesStorage:
          storage: 'Flownative\Google\CloudStorage\GcsStorage'
          storageOptions:
            bucket: 'storage.example.net'
            keyPrefix: '/'
      collections:
        # Collection which contains all persistent resources
        persistent:
          storage: 'googlePersistentResourcesStorage'
          target: 'googlePersistentResourcesTarget'
      targets:
        localWebDirectoryPersistentResourcesTarget:
          target: 'Neos\Flow\ResourceManagement\Target\FileSystemTarget'
          targetOptions:
            path: '%FLOW_PATH_WEB%_Resources/Persistent/'
            baseUri: '_Resources/Persistent/'
            subdivideHashPathSegment: false
        googlePersistentResourcesTarget:
          target: 'Flownative\Google\CloudStorage\GcsTarget'
          targetOptions:
            bucket: 'target.example.net'
            keyPrefix: '/'
            baseUri: 'http://storage.googleapis.com/target.example.net/'

Flownative:
  Google:
    CloudStorage:
      profiles:
        default:
          credentials:
            privateKeyJsonPathAndFilename: 'Data/Secrets/MyGoogleProject-abc123457def.json'