

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

# 自定义范围多租户最佳实践
<a name="scope-based-multi-tenancy"></a>

Amazon Cognito 支持[资源](cognito-user-pools-define-resource-servers.md)服务器的自定义 OAuth 2.0 范围。您可以在用户池中实现具有自定义范围的 machine-to-machine (M2M) 授权模型的应用程序客户端多租户。基于范围的多租户可以在应用程序客户端或应用程序配置中定义访问权限，从而可减少实施 M2M 多租户所需的工作量。

 下图说明了自定义范围多租户的一个选项。该图显示，每个租户都有一个专用的应用程序客户端，可以访问用户池中的相关范围。

![\[此图说明了多租户架构中自定义范围的流程。\]](http://docs.aws.amazon.com/zh_cn/cognito/latest/developerguide/images/multi-tenancy-custom-scope.png)


**何时实施自定义范围多租户**  
 当您的使用场景是机器到机器（M2M）授权，且机密客户端使用客户端凭证来进行授权时。作为一项最佳实践，请创建应用程序客户端专用的资源服务器。自定义范围多租户可以*取决于请求*，也可以*取决于客户端*。

**取决于请求**  
 实施应用程序逻辑，仅请求符合租户要求的范围。例如，应用程序客户端也许可以授予对 API A 和 API B 的读取和写入权限，但租户应用程序 A 仅请求 API A 的读取范围和表示租赁的范围。利用此模型可对租户之间的共享范围进行更复杂的组合。

**取决于客户端**  
 在授权请求中请求分配给应用程序客户端的所有范围。为此，可以在向 [令牌端点](token-endpoint.md) 发出的请求中忽略 `scope` 请求参数。利用此模型可让应用程序客户端存储您要添加到自定义范围的访问指示器。

 无论是哪种情况，应用程序收到的访问令牌中的范围都会表明它们对依赖的数据来源所具备的权限。范围还可以向您的应用程序提供其他信息：
+ 指定租赁
+ 参与请求日志的记录
+ 指明 APIs 该应用程序已被授权查询
+ 告知关于活跃客户的初步检查。

**工作量水平**  
 根据应用程序的规模，自定义范围多租户需要不同的工作量。必须将应用程序逻辑设计为允许应用程序解析访问令牌并发出相应的 API 请求。

 例如，资源服务器范围的格式为 `[resource server identifier]/[name]`。资源服务器标识符不太可能与租户范围的授权决策相关，因此需要一致地解析范围名称。

## 示例资源
<a name="scope-based-multi-tenancy-example"></a>

 以下 AWS CloudFormation 模板使用一个资源服务器和一个应用程序客户端为自定义范围的多租户创建用户池。

```
AWSTemplateFormatVersion: "2010-09-09"
Description: A sample template illustrating scope-based multi-tenancy
Resources:
  MyUserPool:
    Type: "AWS::Cognito::UserPool"
  MyUserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      UserPoolId: !Ref MyUserPool
      # Note that the value for "Domain" must be unique across all of AWS.
      # In production, you may want to consider using a custom domain.
      # See: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html#cognito-user-pools-add-custom-domain-adding
      Domain: !Sub "example-userpool-domain-${AWS::AccountId}"
  MyUserPoolResourceServer:
    Type: "AWS::Cognito::UserPoolResourceServer"
    Properties:
      Identifier: resource1
      Name: resource1
      Scopes:
        - ScopeDescription: Read-only access
          ScopeName: readScope
      UserPoolId: !Ref MyUserPool
  MyUserPoolTenantBatch1ResourceServer:
    Type: "AWS::Cognito::UserPoolResourceServer"
    Properties:
      Identifier: TenantBatch1
      Name: TenantBatch1
      Scopes:
        - ScopeDescription: tenant1 identifier
          ScopeName: tenant1
        - ScopeDescription: tenant2 identifier
          ScopeName: tenant2
      UserPoolId: !Ref MyUserPool
  MyUserPoolClientTenant1:
    Type: "AWS::Cognito::UserPoolClient"
    Properties:
      AllowedOAuthFlows:
        - client_credentials
      AllowedOAuthFlowsUserPoolClient: true
      AllowedOAuthScopes:
        - !Sub "${MyUserPoolTenantBatch1ResourceServer}/tenant1"
        - !Sub "${MyUserPoolResourceServer}/readScope"
      GenerateSecret: true
      UserPoolId: !Ref MyUserPool
Outputs:
  UserPoolClientId:
    Description: User pool client ID
    Value: !Ref MyUserPoolClientTenant1
  UserPoolDomain:
    Description: User pool domain
    Value: !Sub "https://${MyUserPoolDomain}.auth.${AWS::Region}.amazoncognito.com"
```