身份验证与授权

本部分介绍与 Fleet Engine 集成相关的身份验证和授权概念。

您可以通过 Google Cloud 控制台配置 Last Mile Fleet 解决方案提供的功能。Fleet Engine SDK 需要使用已由相应服务帐号签名的 JSON Web 令牌 (JWT)。

概览

客户后端对 Fleet Engine 进行身份验证和授权应使用标准应用默认凭据机制。

Fleet Engine 还会收到来自低信任环境(例如智能手机和浏览器)的调用。为了保护仅适用于可信环境的服务帐号密钥,客户后端应生成带有 Fleet Engine 专用的额外声明的已签名 JSON Web 令牌 (JWT),然后可将其发布到手机等不受信任的环境。

身份验证设计原则

Fleet Engine 的身份验证流程包含以下设计原则。

  • IAM 角色定义了对主账号允许的资源的一组权限。例如,管理员角色可以使用应用默认凭据执行所有操作,而不受信任的驱动程序* 角色只能更新车辆位置,并且只能使用 JWT 进行身份验证和授权。

  • 对于不受信任的环境,JWT 声明会进一步限制调用方可操作的实体。可以是特定任务或送货车辆。

  • 在低信任环境中运行的代码必须首先调用在可信环境中运行的代码,以发出 JWT。

  • Fleet Engine 会对资源的 API 调用执行以下安全检查:

    1. 调用主账号拥有适当的权限(通过角色分配),可以执行对资源执行的操作。

    2. 对于非管理员角色,请求中传递的 JWT 声明为资源提供必要的权限。

身份验证流程

以下序列图演示了这些身份验证流程的详细信息。

  1. 舰队管理员会创建服务账号。

  2. 舰队管理员为服务账号分配特定的 IAM 角色。

  3. 舰队管理员使用服务帐号和应用默认凭据配置其后端。

  4. 客户端应用从客户后端请求 JWT。请求者可以是驱动程序应用、消费者应用或监控应用。

  5. 客户后端为相应的服务帐号签名并颁发 JWT。客户端应用接收 JWT。

  6. 客户端应用使用 JWT 连接到 Fleet Engine 以读取或修改数据,具体取决于在设置阶段分配给它的 IAM 角色。

身份验证序列图

Cloud 项目设置

如需设置云项目,请先创建项目,然后再创建服务帐号。

如需创建 Google Cloud 项目,请执行以下操作:

  1. 使用 Google Cloud 控制台创建 Google Cloud 项目。
  2. 使用 API 和服务信息中心,启用 Local Rides and Deliveries API。

服务账号和 IAM 角色

服务帐号是一种由应用(而不是个人)使用的特殊帐号。通常,服务帐号用于创建 JWT,以便根据角色授予不同权限集。为了降低滥用的可能性,您可以创建多个服务帐号,每个服务帐号都需要最少的角色集 ()。

Last Mile Fleet 解决方案使用以下角色:

角色说明
Fleet Engine Delivery 可信司机用户

roles/fleetengine.deliveryTrustedDriver
授予创建和更新送货车辆和任务的权限,包括更新送货车辆的位置和任务状态或结果。具有此角色的服务帐号生成的令牌通常从配送司机的移动设备或后端服务器使用。
Fleet Engine Delivery 不受信任的司机用户

roles/fleetengine.deliveryUntrustedDriver
授予更新送货车辆位置的权限。由具有此角色的服务帐号创建的令牌通常在送货司机的移动设备上使用。
Fleet Engine Delivery Consumer User

roles/fleetengine.deliveryConsumer
授予使用跟踪 ID 搜索任务以及读取但不更新任务信息的权限。具有此角色的服务帐号生成的令牌通常通过传送使用方的网络浏览器使用。
Fleet Engine Delivery Admin<>

roles/fleetengine.deliveryAdmin
授予对传送资源的读写权限。具有此角色的主账号不需要使用 JWT,应改用应用默认凭据。自定义 JWT 声明将被忽略。此角色应仅限于受信任的环境(客户后端)。
Fleet Engine Delivery 超级用户 **(已弃用)**

roles/fleetengine.deliverySuperUser
授予对所有配送工具和任务 API 的权限。具有此角色的服务帐号生成的令牌通常使用您的后端服务器。
Fleet Engine Delivery Fleet Reader

roles/fleetengine.deliveryFleetReader
授予读取送货车辆和任务的权限,以及使用跟踪 ID 搜索任务的权限。具有此角色的服务帐号生成的令牌通常通过交付舰队运营商的网络浏览器使用。

如果组织使用由公司 IT 管理的设备为配送司机提供设备,则可以利用 Fleet Engine 可信司机用户角色提供的灵活性,并选择将部分或全部 Fleet Engine 互动集成到移动应用中。

支持“自带设备”政策的组织应选择确保 Fleet Engine 不受信任的司机用户角色的安全性,并且仅依赖移动应用将车辆位置信息更新发送到 Fleet Engine。所有其他互动都应来自客户后端服务器。

驱动程序 SDK 和消费者 SDK 是围绕这些标准角色构建的。但是,您可以创建自定义角色,来允许将一组任意权限捆绑在一起。如果缺少所需权限,驱动程序 SDK 和消费者 SDK 将显示错误消息。因此,我们强烈建议使用上述标准角色,而不是自定义角色。

创建服务账号

您可以使用 Google Cloud 控制台中的 IAM & Admin > Service Accounts 标签页创建服务帐号。从“角色”下拉列表中,选择 Fleet Engine,然后将其中一个角色分配给服务帐号。最好指明与每个角色关联的帐号。例如,为服务账号指定一个有意义的名称。

为方便起见,如果您需要为不受信任的客户端创建 JWT,可以将用户添加到 Service Account Token Creator 角色,这样他们就可以使用 gcloud 命令行工具创建令牌。

gcloud projects add-iam-policy-binding project-id \
       --member=user:my-user@example.com \
       --role=roles/iam.serviceAccountTokenCreator

其中,my-user@example.com 是用于通过 gcloud 进行身份验证的电子邮件地址 (gcloud auth list --format='value(account)')。

Fleet Engine 身份验证库

Fleet Engine 使用 JWT 限制不受信任的环境中对 Fleet Engine API 的访问。GitHub 上提供了 Fleet Engine Auth 库,它简化了 Fleet Engine JWT 的构建并对其进行安全签名。

该库具有以下优势:

  • 简化创建 Fleet Engine 令牌的过程。
  • 提供除使用凭据文件以外的令牌签名机制(例如模拟服务帐号)。

创建 JSON Web 令牌 (JWT) 以进行授权

如果不使用 Fleet Engine Auth 库,您需要直接在代码库中创建 JWT。因此,您需要深入了解 JWT 及其与 Fleet Engine 的关系。因此,我们强烈建议利用 Fleet Engine Auth 库。

在 Fleet Engine 中,JWT 提供短期身份验证,并确保设备只能修改其获得授权的车辆或任务。JWT 包含一个标头和一个声明部分。 标头部分包含要使用的私钥(从服务帐号中获取)和加密算法等信息。声明部分包含如下信息:令牌的创建时间、令牌的存留时间、令牌声明所有权的服务,以及用于缩小访问权限范围的其他授权信息(例如送货车辆 ID)。

JWT 标头部分包含以下字段:

Field说明
alg 要使用的算法。`RS256`。
typ 令牌的类型。“JWT”。
儿童 您的服务帐号的私钥 ID。您可以在服务帐号 JSON 文件的“private_key_id”字段中找到此值。请务必使用具有正确级别权限的服务账号的密钥。

JWT 声明部分包含以下字段:

Field说明
iss 您的服务帐号的电子邮件地址。
sub 您的服务帐号的电子邮件地址。
aud 您的服务账号的 SERVICE_NAME,在本示例中为 https://fleetengine.googleapis.com/
iat 创建令牌时的时间戳,以自 1970 年 1 月 1 日 00:00:00 UTC(世界协调时间)起经过的秒数指定。允许 10 分钟偏差。如果时间戳是过于久远的过去或将来,服务器可能会报告错误。
exp 令牌到期的时间戳,以自世界协调时间 (UTC) 1970 年 1 月 1 日 00:00:00 以来经过的秒数指定。如果时间戳在未来一小时以上,则请求将失败。
授权 根据用例,它可能包含“deliveryvehicleid”“trackingid”“taskid”或“taskids”。

创建 JWT 令牌指的是对其进行签名。如需了解如何创建和为 JWT 签名,请参阅不使用 OAuth 的服务帐号授权。然后,您可以将生成的令牌附加到 gRPC 调用或用于访问 Fleet Engine 的其他方法。

JWT 声明

最后一英里舰队解决方案使用不公开声明。使用私有声明可确保只有获得授权的客户端才能访问自己的数据。例如,当您的后端为送货司机的移动设备颁发 JSON Web 令牌时,该令牌应包含 deliveryvehicleid 声明以及该司机的送货车辆 ID 的值。然后,根据驾驶员角色,令牌仅可访问特定交付车辆 ID,而不能访问任何其他任意车辆 ID。

最后一英里舰队解决方案使用以下不公开声明:

  • deliveryvehicleid - 在调用每辆车的 API 时使用。
  • taskid - 在调用任务级 API 时使用。
  • taskids - 在调用 BatchCreateTasksAPI 时使用。此声明必须采用数组形式,并且该数组应包含完成请求所需的所有任务 ID。请勿包含 delivervehicleidtrackingidtaskid 声明。
  • trackingid - 在调用 GetTaskTrackingInfoAPI 时使用。声明必须与请求中的跟踪 ID 一致。请勿包含 delivervehicleidtaskidtaskids 声明。

当您从后端服务器调用 API 时,该令牌还必须包含相应的声明,但您可以对 deliveryvehicleidtaskidtrackingid 声明使用星号(“*”)的特殊值。星号(“*”)也可以在 taskids 声明中使用,但它必须是数组中的唯一元素。

如果您希望直接以令牌不记名的形式创建 JSON 并为其签名,而不是使用 OAuth 2.0 访问令牌,请参阅 Identity Developer 文档中的不使用 OAuth 的服务帐号授权说明。

将令牌附加到 gRPC 调用的机制取决于用于进行调用的语言和框架。为 HTTP 调用指定令牌的机制是添加带有不记名令牌的授权标头,其值为令牌,如各个运单跟踪舰队性能用例的授权说明中所述。

以下示例展示了后端服务器中每个任务的操作的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_provider_service_account"
    }
    .
    {
      "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
      "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "taskid": "*"
       }
    }

以下示例展示了从后端服务器执行批量创建任务操作的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_provider_service_account"
    }
    .
    {
      "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
      "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "taskids": ["*"]
       }
    }

以下示例展示了来自后端服务器的每个送货车辆操作的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_provider_service_account"
    }
    .
    {
      "iss": "provider@yourgcpproject.iam.gserviceaccount.com",
      "sub": "provider@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "deliveryvehicleid": "*"
       }
    }

以下示例展示了面向最终用户客户的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_delivery_consumer_service_account"
    }
    .
    {
      "iss": "consumer@yourgcpproject.iam.gserviceaccount.com",
      "sub": "consumer@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "trackingid": "shipment_12345"
       }
    }

以下示例显示了您的驱动程序应用的令牌:

    {
      "alg": "RS256",
      "typ": "JWT",
      "kid": "private_key_id_of_delivery_driver_service_account"
    }
    .
    {
      "iss": "driver@yourgcpproject.iam.gserviceaccount.com",
      "sub": "driver@yourgcpproject.iam.gserviceaccount.com",
      "aud": "https://fleetengine.googleapis.com/",
      "iat": 1511900000,
      "exp": 1511903600,
      "authorization": {
         "deliveryvehicleid": "driver_12345"
       }
    }
  • 对于标头中的 kid 字段,请指定服务帐号的私钥 ID。您可以在服务帐号 JSON 文件的 private_key_id 字段中找到此值。
  • 对于 isssub 字段,请指定您的服务帐号的电子邮件地址。您可以在服务帐号 JSON 文件的 client_email 字段中找到此值。
  • 对于 aud 字段,请指定 https://SERVICE_NAME/
  • 对于 iat 字段,请指定创建令牌时的时间戳,以自 1970 年 1 月 1 日 00:00:00 UTC 以来经过的秒数。允许 10 分钟偏差。如果时间戳是过于久远的过去或将来,服务器可能会报告错误。
  • 对于 exp 字段,请指定令牌到期时的时间戳,以自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数表示。建议值为 iat + 3600。

对要传递给移动设备或最终用户的令牌进行签名时,请务必使用交付司机或消费者角色的凭据文件。否则,移动设备或最终用户将能够更改或查看他们无权访问的信息。