

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 示例 4：使用 RBAC 和 ABAC 进行多租户访问控制
<a name="avp-mt-abac-rbac-examples"></a>

为了增强上一节中的 RBAC 示例，您可以向用户添加属性，以创建用于多租户访问控制的 RBAC-ABAC 混合方法。此示例包含与上一个示例相同的角色，但添加了用户属`account_lockout_flag`性和上下文参数`uses_mfa`。该示例还采用了不同的方法来实现多租户访问控制，即同时使用 RBAC 和 ABAC，并为每个租户使用一个共享策略存储而不是不同的策略存储。

![使用 RBAC、ABAC、Amazon 验证权限和 Cedar 进行多租户访问控制的示例](http://docs.aws.amazon.com/zh_cn/prescriptive-guidance/latest/saas-multitenant-api-access-authorization/images/avp-example-4.png)


此示例表示一种多租户 SaaS 解决方案，在该解决方案中，您需要为租户 A 和租户 B 提供授权决策，与前面的示例类似。

为了实现用户锁定功能，该示例在授权请求中`account_lockout_flag`向`User`实体委托人添加了该属性。此标志锁定用户对系统的访问权限，并将`DENY`所有权限授予被锁定的用户。该`account_lockout_flag`属性与`User`实体相关联，在多个会话中主动撤消该标志`User`之前一直有效。该示例使用`when`条件进行评估`account_lockout_flag`。

该示例还添加了有关请求和会话的详细信息。上下文信息指定已使用多因素身份验证对会话进行身份验证。为了实现此验证，该示例使用`when`条件来评估作为上下文字段一部分的`uses_mfa`标志。有关添加上下文的最佳做法的更多信息，请参阅 [Cedar 文档](https://docs.cedarpolicy.com/auth/entities-syntax.html)。

```
permit (
    principal in MultitenantApp::Role::"allAccessRole",
    action in [
        MultitenantApp::Action::"viewData",
        MultitenantApp::Action::"updateData"
    ],
    resource
)
when {
    principal.account_lockout_flag == false &&
    context.uses_mfa == true &&
    resource in principal.Tenant
};
```

除非资源与请求委托人的`Tenant`属性属于同一组，否则此策略禁止访问资源。这种维护租户隔离的方法被称为 “*一个共享的多租户策略存储*” 方法。有关多租户 SaaS 应用程序的已验证权限设计注意事项的更多信息，请参阅[已验证权限多租户设计注意事项部分](avp-design-considerations.md)。

该政策还确保委托人是`allAccessRole`和的成员，并将操作限制为`viewData`和。`updateData`此外，此策略还会验证即`account_lockout_flag`为`false`以及上下文值的`uses_mfa`计算结果是否为。`true`

同样，以下策略可确保委托人和资源都与同一个租户相关联，从而防止跨租户访问。该政策还确保委托人是其成员，`viewDataRole`并将操作限制为。`viewData`此外，它还会验证是否`account_lockout_flag`为，`false`以及的上下文值的`uses_mfa`计算结果是否为。`true`

```
permit (
    principal in MultitenantApp::Role::"viewDataRole",
    action == MultitenantApp::Action::"viewData",
    resource
)
when {
    principal.account_lockout_flag == false &&
    context.uses_mfa == true &&
    resource in principal.Tenant
};
```

第三个策略与前一个策略类似。该策略要求资源必须是与所代表的实体相对应的组的成员`principal.Tenant`。这样可以确保委托人和资源都与租户 B 相关联，从而防止跨租户访问。该政策确保委托人是其成员，`updateDataRole`并限制其操作。`updateData`此外，此策略还会验证是否`account_lockout_flag`为，`false`以及的上下文值是否`uses_mfa`计算为。`true`

```
permit (
    principal in MultitenantApp::Role::"updateDataRole",
    action == MultitenantApp::Action::"updateData",
    resource
)
when {
    principal.account_lockout_flag == false &&
    context.uses_mfa == true &&
    resource in principal.Tenant
};
```

以下授权请求由本节前面讨论的三个策略进行评估。在此授权请求中，类型为`User`且值为的委托人向该角色`Alice`发出`updateData`请求`allAccessRole`。 `Alice`的属性的`Tenant`值为`Tenant::"TenantA"`。正在尝试执行的操作`Alice`是，`updateData,`并且要应用该操作`SampleData`的资源属于该类型`Data`。 `SampleData`已`TenantA`作为父实体。

根据策略存储中的第一个`<DATAMICROSERVICE_POLICYSTOREID>`策略，`Alice`可以对资源执行操作，前提是满足策略`when`条款中的条件。`updateData`第一个条件要求`principal.Tenant`属性计算为`TenantA`。第二个条件要求委托人的属性`account_lockout_flag`为`false`。最后一个条件要求上下文`uses_mfa`必须是`true`。由于所有三个条件都已满足，因此请求会返回一个`ALLOW`决定。

```
{
  "policyStoreId": "DATAMICROSERVICE_POLICYSTORE",
  "principal": {
      "entityType": "MultitenantApp::User",
      "entityId": "Alice"
  },
  "action": {
      "actionType": "MultitenantApp::Action",
      "actionId": "updateData"
  },
  "resource": {
      "entityType": "MultitenantApp::Data",
      "entityId": "SampleData"
  },
  "context": {
    "contextMap": {
        "uses_mfa": {
            "boolean": true
        }
    }
  },
  "entities": {
    "entityList": [
      {
        "identifier": {
            "entityType": "MultitenantApp::User",
            "entityId": "Alice"
        },
        "attributes": {
            {
                "account_lockout_flag": {
                    "boolean": false
                },
                "Tenant": {
                   "entityIdentifier": {
                        "entityType":"MultitenantApp::Tenant",
                        "entityId":"TenantA"
                   }
                }
            }
        },
        "parents": [
            {
                "entityType": "MultitenantApp::Role",
                "entityId": "allAccessRole"
            }
        ]
        },
     {
        "identifier": {
            "entityType": "MultitenantApp::Data",
            "entityId": "SampleData"
        },
        "attributes": {},
        "parents": [
            {
                "entityType": "MultitenantApp::Tenant",
                "entityId": "TenantA"
            }
        ]
      }
    ]
  }
}
```