

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Configurando autorização e autenticação para proteger seu GraphQL APIs
<a name="security-authz"></a>

AWS AppSync oferece os seguintes tipos de autorização para proteger o GraphQL APIs: chaves de API, Lambda, IAM, OpenID Connect e grupos de usuários do Cognito. Cada opção fornece um método diferente de segurança: 

1. **Autorização de chave de API**: controla a limitação de dados não autenticados APIs, fornecendo uma opção de segurança simples. 

1. **Autorização do Lambda**: permite uma lógica de autorização personalizada, explicando as entradas e saídas da função em detalhes. 

1. **Autorização do IAM**: utiliza AWS o processo de assinatura da versão 4 da assinatura, permitindo um controle de acesso refinado por meio de políticas do IAM. 

1. **Autorização do OpenID Connect**: integra-se aos serviços compatíveis com OIDC para autenticação do usuário. 

1. **Grupos de usuários do Cognito**: implementa o controle de acesso baseado em grupo usando os atributos de gerenciamento de usuários do Cognito. 

## Tipos de autorização
<a name="authorization-types"></a>

Há cinco maneiras de autorizar aplicativos a interagir com sua API AWS AppSync GraphQL. Você especifica qual tipo de autorização você usa especificando um dos seguintes valores de tipo de autorização em sua chamada de AWS AppSync API ou CLI:
+   
** `API_KEY` **  
Para usar chaves da API.
+   
** `AWS_LAMBDA` **  
Para usar uma AWS Lambda função.
+   
** `AWS_IAM` **  
Para usar permissões AWS Identity and Access Management ([IAM](https://aws.amazon.com/iam/)).
+   
** `OPENID_CONNECT` **  
Para usar o provedor OpenID Connect.
+   
** `AMAZON_COGNITO_USER_POOLS` **  
Para usar um grupo de usuários do Amazon Cognito.

Esses tipos de autorização básicos funcionam para a maioria dos desenvolvedores. Para casos de uso mais avançados, é possível adicionar modos de autorização adicionais por meio do console, da CLI e do AWS CloudFormation. Para modos de autorização adicionais, AWS AppSync fornece um tipo de autorização que usa os valores listados acima (ou seja`API_KEY`,`AWS_LAMBDA`,`AWS_IAM`,`OPENID_CONNECT`, e`AMAZON_COGNITO_USER_POOLS`).

Ao especificar `API_KEY`, `AWS_LAMBDA` ou `AWS_IAM` como o tipo de autorização principal ou padrão, não é possível especificá-los novamente como um dos modos de autorização adicionais. Da mesma forma, você não pode duplicar `API_KEY`, `AWS_LAMBDA` ou `AWS_IAM` nos modos de autorização adicionais. É possível usar vários grupos de usuários do Amazon Cognito e provedores do OpenID Connect. No entanto, você não pode usar grupos de usuários do Amazon Cognito nem provedores do OpenID Connect duplicados entre o modo de autorização padrão e qualquer um dos outros modos de autorização. É possível especificar clientes diferentes para o grupo de usuários do Amazon Cognito ou o provedor do OpenID Connect usando a expressão regular de configuração correspondente.

Quando você salva as alterações na configuração da sua API, AWS AppSync começa a propagar as alterações. Até que sua alteração de configuração seja propagada, AWS AppSync continue veiculando seu conteúdo da configuração anterior. Depois que sua alteração de configuração for propagada, AWS AppSync imediatamente começará a veicular seu conteúdo com base na nova configuração. Enquanto AWS AppSync propagamos suas alterações para uma API, não podemos determinar se a API está veiculando seu conteúdo com base na configuração anterior ou na nova configuração.

## API\$1KEY autorização
<a name="api-key-authorization"></a>

Os não autenticados APIs exigem uma limitação mais rígida do que os autenticados. APIs Uma maneira de verificar o controle de utilização para endpoints GraphQL não autenticados é por meio do uso de chaves da API. Uma chave da API é um valor codificado no aplicativo que é gerado pelo serviço AWS AppSync ao criar um endpoint GraphQL não autenticado. Você pode rotacionar as chaves de API no console, da CLI ou da [Referência da API do AWS AppSync](https://docs.aws.amazon.com/appsync/latest/APIReference/).

------
#### [ Console ]

1. Faça login no Console de gerenciamento da AWS e abra o [AppSync console](https://console.aws.amazon.com/appsync/).

   1. No **APIs painel**, escolha sua API GraphQL.

   1. Na **barra lateral**, escolha **Configurações**.

1. Em **Modo de autorização padrão**, escolha **Chave de API**.

1. Na tabela **chaves de API**, escolha **Adicionar chave de API**.

   Uma nova chave de API será gerada na tabela.

   1. Para excluir uma chave de API antiga, selecione a chave de API na tabela e escolha **Excluir**.

1. Escolha **Salvar** na parte inferior da página.

------
#### [ CLI ]

1. Se você ainda não tiver feito isso, configure seu acesso à AWS CLI. Para obter mais informações, consulte [Noções básicas de configuração](https://docs.aws.amazon.com//cli/latest/userguide/cli-configure-quickstart.html).

1. Crie um objeto da API GraphQL executando o comando [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-graphql-api.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-graphql-api.html).

   Você precisará digitar dois parâmetros para esse comando específico:

   1. O `api-id` da sua API GraphQL.

   1. O novo `name` da sua API. Você pode usar o mesmo `name`.

   1. O `authentication-type`, que será `API_KEY`.
**nota**  
Existem outros parâmetros, como `Region`, que devem ser configurados, mas geralmente usam como padrão os valores de configuração da CLI.

   Veja um exemplo de comando:

   ```
   aws appsync update-graphql-api --api-id abcdefghijklmnopqrstuvwxyz --name TestAPI --authentication-type API_KEY
   ```

   Uma saída será retornada na CLI. Aqui está um exemplo em JSON:

   ```
   {
       "graphqlApi": {
           "xrayEnabled": false,
           "name": "TestAPI",
           "authenticationType": "API_KEY",
           "tags": {},
           "apiId": "abcdefghijklmnopqrstuvwxyz",
           "uris": {
               "GRAPHQL": "https://s8i3kk3ufhe9034ujnv73r513e.appsync-api.us-west-2.amazonaws.com/graphql",
               "REALTIME": "wss://s8i3kk3ufhe9034ujnv73r513e.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
           },
           "arn": "arn:aws:appsync:us-west-2:348581070237:apis/abcdefghijklmnopqrstuvwxyz"
       }
   }
   ```

------

As chaves da API são configuráveis para até 365 dias e é possível estender uma data de expiração existente para mais 365 dias a partir dessa data. As chaves da API são recomendadas para fins de desenvolvimento ou casos de uso em que é seguro expor uma API pública.

No cliente, a chave da API é especificada pelo cabeçalho `x-api-key`.

Por exemplo, se o `API_KEY` for `'ABC123'`, envie uma consulta do GraphQL via `curl` da seguinte forma:

```
$ curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
```

## AWS\$1LAMBDA autorização
<a name="aws-lambda-authorization"></a>

Você pode implementar sua própria lógica de autorização de API usando uma AWS Lambda função. Você pode usar uma função do Lambda para seu autorizador primário ou secundário, mas pode haver somente uma função de autorização do Lambda por API. Ao usar funções do Lambda para autorização, o seguinte se aplica:
+ Se a API tiver os modos de autorização `AWS_IAM` e `AWS_LAMBDA` habilitados, a assinatura do SigV4 não poderá ser usada como token de autorização do `AWS_LAMBDA`.
+ Se a API tiver os modos de autorização `AWS_LAMBDA`, `OPENID_CONNECT` ou `AMAZON_COGNITO_USER_POOLS` habilitados, o token do OIDC não poderá ser usado como token de autorização do `AWS_LAMBDA`. Observe que o token OIDC pode ser um esquema do Bearer.
+ Uma função do Lambda não deve retornar mais de 5 MB de dados contextuais para os resolvedores.

Por exemplo, se o token de autorização for `'ABC123'`, envie uma consulta do GraphQL via curl da seguinte forma: 

```
$ curl -XPOST -H "Content-Type:application/graphql" -H "Authorization:ABC123" -d '{ "query":
         "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql
```

As funções do Lambda são chamadas antes de cada consulta ou mutação. O valor de retorno pode ser armazenado em cache com base no ID da API e no token de autenticação. Quando uma resposta do autorizador Lambda tem menos de 1.048.576 bytes, armazena em cache a resposta para solicitações subsequentes. AWS AppSync Se a resposta do autorizador Lambda for igual ou maior que 1.048.576 bytes, AWS AppSync não armazena a resposta em cache e invoca o autorizador Lambda para cada solicitação recebida. Para otimizar o desempenho e minimizar os custos de invocação do Lambda, recomendamos a você limitar as respostas de autorizador do Lambda a 1.048.576 bytes. Por padrão, o armazenamento em cache não está habilitado, mas isso pode ser habilitado no nível da API ou definindo o valor `ttlOverride` no valor de retorno de uma função. 

Uma expressão regular que valida os tokens de autorização antes que a função seja chamada pode ser especificada, se desejado. Essas expressões regulares são usadas para validar se um token de autorização está no formato correto antes de sua função ser chamada. Qualquer solicitação que use um token que não corresponda a essa expressão regular será negada automaticamente. 

As funções Lambda usadas para autorização exigem que uma política principal seja aplicada `appsync.amazonaws.com` a elas AWS AppSync para permitir sua chamada. Essa ação é feita automaticamente no AWS AppSync console; o AWS AppSync console *não* remove a política. Para obter mais informações sobre como anexar políticas às funções do Lambda, [consulte Políticas baseadas em recursos](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) no Guia do desenvolvedor. AWS Lambda 

A função do Lambda que você especificar receberá um evento com a seguinte forma:

```
{
    "authorizationToken": "ExampleAUTHtoken123123123",
    "requestContext": {
        "apiId": "aaaaaa123123123example123",
        "accountId": "111122223333",
        "requestId": "f4081827-1111-4444-5555-5cf4695f339f",
        "queryString": "mutation CreateEvent {...}\n\nquery MyQuery {...}\n",
        "operationName": "MyQuery",
        "variables": {}
    }
    "requestHeaders": {
        application request headers
    }
}
```

O `event` objeto contém os cabeçalhos que foram enviados na solicitação do cliente do aplicativo para AWS AppSync.

A função de autorização deve retornar pelo menos `isAuthorized` um booleano indicando se a solicitação foi autorizada. AWS AppSync reconhece as seguintes chaves retornadas das funções de autorização do Lambda:

**nota**  
O valor da operação `operationName` in the `requestContext` for a WebSocket connect é definido AWS AppSync como "`DeepDish:Connect`”.

### Lista de funções
<a name="aws-lambda-authorization-list"></a>

`isAuthorized` (booleano, obrigatório)  
Um valor booleano indicando se o valor no `authorizationToken` está autorizado a fazer chamadas para a API GraphQL.  
Se esse valor for verdadeiro, a execução da API GraphQL continuará. Se esse valor for falso, um `UnauthorizedException` será gerado.

`deniedFields` (lista de strings, opcional)  
Uma lista que é alterada à força para `null`, mesmo que um valor tenha sido retornado de um resolvedor.  
Cada item é um ARN de campo totalmente qualificado na forma de `arn:aws:appsync:us-east-1:111122223333:apis/GraphQLApiId/types/TypeName/fields/FieldName` ou uma forma abreviada de `TypeName.FieldName`. O formulário ARN completo deve ser usado quando dois APIs compartilham um autorizador de função Lambda e pode haver ambigüidade entre tipos e campos comuns entre os dois. APIs

`resolverContext` (objeto JSON, opcional)  
Um objeto JSON visível como `$ctx.identity.resolverContext` nos modelos de resolvedor. Por exemplo, se a estrutura a seguir for retornada por um resolvedor:  

```
{
  "isAuthorized":true
  "resolverContext": {
    "banana":"very yellow",
    "apple":"very green" 
  }
}
```
O valor de `ctx.identity.resolverContext.apple` nos modelos do resolvedor será "`very green`”. O objeto `resolverContext` é compatível apenas com pares de chave-valor. Não há suporte para chaves aninhadas.  
O tamanho total desse objeto JSON não deve exceder 5 MB.

`ttlOverride` (inteiro, opcional)  
O número de segundos que deve levar para a resposta ser armazenada em cache. Se nenhum valor for retornado, o valor da API será usado. Se for 0, a resposta não será armazenada em cache.

Os autorizadores Lambda têm um tempo limite padrão de 10 segundos, mas podem expirar mais cedo em condições de pico de tráfego. Recomendamos criar funções para serem executadas no menor tempo possível (menos de 1s) para escalar o desempenho da sua API.

Vários AWS AppSync APIs podem compartilhar uma única função Lambda de autenticação. O uso de autorizadores entre contas não é permitido.

Ao compartilhar uma função de autorização entre várias APIs, esteja ciente de que nomes de campo abreviados (`typename.fieldname`) podem ocultar campos inadvertidamente. Para eliminar a ambiguidade de um campo em `deniedFields`, você pode especificar um ARN de campo não ambíguo na forma de `arn:aws:appsync:region:accountId:apis/GraphQLApiId/types/typeName/fields/fieldName`. 

Para adicionar uma função do Lambda como o modo de autorização padrão em AWS AppSync:

------
#### [ Console ]

1. Faça login no AWS AppSync console e navegue até a API que você deseja atualizar.

1. Navegue até a página Configurações da sua API.

   Mude a autorização no nível da API para **AWS Lambda**.

1. Escolha o ARN Região da AWS e o Lambda para autorizar chamadas de API.
**nota**  
A política entidade principal principal apropriada será adicionada automaticamente, permitindo que AWS AppSync chame sua função do Lambda. 

1. Opcionalmente, defina o TTL de resposta e a expressão regular de validação de token.

------
#### [ AWS CLI ]

1. Anexe a seguinte política à função do Lambda que está sendo usada:

   ```
   aws lambda add-permission --function-name "my-function" --statement-id "appsync" --principal appsync.amazonaws.com --action lambda:InvokeFunction --output text 
   ```
**Importante**  
Se você quiser que a política da função seja bloqueada em uma única API GraphQL, você pode executar este comando:  

   ```
   aws lambda add-permission --function-name “my-function” --statement-id “appsync” --principal appsync.amazonaws.com --action lambda:InvokeFunction --source-arn “<my AppSync API ARN>” --output text
   ```

1. Atualize sua AWS AppSync API para usar a função ARN do Lambda fornecida como autorizadora:

   ```
   aws appsync update-graphql-api --api-id example2f0ur2oid7acexample --name exampleAPI --authentication-type AWS_LAMBDA --lambda-authorizer-config authorizerUri="arn:aws:lambda:us-east-2:111122223333:function:my-function"
   ```
**nota**  
Você também pode incluir outras opções de configuração, como a expressão regular do token. 

------

O exemplo a seguir descreve uma função do Lambda que demonstra os vários estados de autenticação e falha que uma função do Lambda pode ter quando usada como mecanismo de autorização do AWS AppSync :

```
def handler(event, context):
  # This is the authorization token passed by the client
  token = event.get('authorizationToken')
  # If a lambda authorizer throws an exception, it will be treated as unauthorized. 
  if 'Fail' in token:
    raise Exception('Purposefully thrown exception in Lambda Authorizer.')

  if 'Authorized' in token and 'ReturnContext' in token:
    return {
      'isAuthorized': True,
      'resolverContext': {
        'key': 'value'
      }
    }

  # Authorized with no f
  if 'Authorized' in token:
    return {
      'isAuthorized': True
    }
  # Partial authorization
  if 'Partial' in token:
    return {
      'isAuthorized': True,
      'deniedFields':['user.favoriteColor']
    }
  if 'NeverCache' in token:
    return {
      'isAuthorized': True,
      'ttlOverride': 0
    }
  if 'Unauthorized' in token:
    return {
      'isAuthorized': False
    }
  # if nothing is returned, then the authorization fails. 
  return {}
```

### Como contornar as limitações de autorização de tokens do SigV4 e OIDC
<a name="aws-lambda-authorization-create-new-auth-token"></a>

Os métodos a seguir podem ser usados para contornar o problema de não ser possível usar sua assinatura do SigV4 ou token do OIDC como seu token de autorização do Lambda quando determinados modos de autorização estão habilitados.

Se você quiser usar a assinatura do SigV4 como token de autorização do Lambda quando os modos de autorização do `AWS_IAM` e `AWS_LAMBDA` estiverem habilitados para a API, faça AWS AppSync o seguinte:
+ Para criar um novo token de autorização Lambda, adicione and/or prefixos de sufixos aleatórios à assinatura SigV4.
+ Para recuperar a assinatura SigV4 original, atualize sua função Lambda removendo os and/or sufixos aleatórios do token de autorização do Lambda. Em seguida, use a assinatura original do SigV4 para autenticação.

Se você quiser usar o token OIDC como o token de autorização Lambda quando o modo de autorização ou os modos de `OPENID_CONNECT` autorização `AMAZON_COGNITO_USER_POOLS` e de `AWS_LAMBDA` autorização estiverem habilitados para a API, AWS AppSync faça o seguinte:
+ Para criar um novo token de autorização Lambda, adicione and/or prefixos de sufixos aleatórios ao token OIDC. O token de autorização do Lambda não deve conter um prefixo do esquema do Bearer.
+ Para recuperar o token OIDC original, atualize sua função do Lambda removendo os and/or sufixos aleatórios do token de autorização do Lambda. Em seguida, use o token original do OIDC para autenticação.

## AWS\$1IAM autorização
<a name="aws-iam-authorization"></a>

Esse tipo de autorização impõe o [processo de assinatura versão 4 da assinatura AWS](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) na API GraphQL. Associe políticas de acesso do Identity and Access Management ([IAM](https://aws.amazon.com/iam/)) com esse tipo de autorização. A aplicação pode aproveitar essa associação ao usar uma chave de acesso (que consiste em um ID de chave de acesso e chave de acesso secreta) ou usando credenciais temporárias de curta duração fornecidas por identidades federadas do Amazon Cognito.

Se quiser um perfil com acesso para realizar todas as operações de dados:

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "appsync:GraphQL"
         ],
         "Resource": [
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/*"
         ]
      }
   ]
}
```

------

Você pode encontrar na página principal `YourGraphQLApiId` de listagem de APIs no AppSync console, diretamente abaixo do nome da sua API. Como alternativa, você pode recuperá-lo com a CLI: `aws appsync list-graphql-apis` 

Se desejar restringir o acesso somente a determinadas operações do GraphQL, faça isso para os campos `Query`, `Mutation` e `Subscription` raiz.

------
#### [ JSON ]

****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Action": [
            "appsync:GraphQL"
         ],
         "Resource": [
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-1>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/<Field-2>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Mutation/fields/<Field-1>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Subscription/fields/<Field-1>"
         ]
     }
   ]
}
```

------

Por exemplo, suponha que tenha o seguinte esquema e deseje restringir o acesso à obtenção de todas as postagens:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
}
```

A política do IAM correspondente para uma função (que pode ser anexada a um banco de identidades do Amazon Cognito, por exemplo) seria semelhante ao seguinte:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
            "appsync:GraphQL"
            ],
            "Resource": [
                "arn:aws:appsync:us-west-2:123456789012:apis/YourGraphQLApiId/types/Query/fields/posts"
            ]
        }
    ]
}
```

------

## OPENID\$1CONNECT autorização
<a name="openid-connect-authorization"></a>

Esse tipo de autorização impõe tokens do [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) (OIDC) fornecidos por um serviço compatível com o OIDC. O aplicativo pode aproveitar os usuários e os privilégios definidos pelo provedor de OIDC para controlar o acesso.

Um URL emissor é o único valor de configuração obrigatório que deve ser fornecido ao AWS AppSync, por exemplo, `https://auth.example.com`. Esse URL deve ser endereçável por HTTPS. AWS AppSync `/.well-known/openid-configuration`[anexa ao URL do emissor e localiza a configuração do OpenID de acordo com a especificação do `https://auth.example.com/.well-known/openid-configuration` OpenID Connect Discovery.](https://openid.net/specs/openid-connect-discovery-1_0.html) Ele espera recuperar um documento JSON [RFC5785](https://tools.ietf.org/html/rfc5785)compatível nesse URL. Esse documento JSON deve conter uma `jwks_uri` chave, que aponta para o documento JSON Web Key Set (JWKS) com as chaves de assinatura. AWS AppSync exige que o JWKS contenha campos JSON de e. `kty` `kid`

AWS AppSync suporta uma ampla variedade de algoritmos de assinatura.


| Algoritmos de assinatura | 
| --- | 
| RS256 | 
| RS384 | 
| RS512 | 
| PS256 | 
| PS384 | 
| PS512 | 
| HS256 | 
| HS384 | 
| HS512 | 
| ES256 | 
| ES384 | 
| ES512 | 

Recomendamos que você use os algoritmos do RSA. Os tokens emitidos pelo provedor devem incluir a hora em que o token foi emitido (`iat`) e pode incluir a hora em que foi autenticado (`auth_time`). Você pode fornecer valores de TTL para a hora de emissão (`iatTTL`) e a hora de autenticação (`authTTL`) na configuração do OpenID Connect para validação adicional. Se o provedor autoriza vários aplicativos, você também pode fornecer uma expressão regular (`clientId`) usada para autorizar por ID de cliente. Quando o `clientId` está presente em sua configuração do OpenID Connect, AWS AppSync valida a declaração exigindo que a corresponda `clientId` à `azp` reivindicação `aud` ou à reivindicação no token.

Para validar vários clientes, IDs use o operador de pipeline (“\$1”), que é um “ou” na expressão regular. Por exemplo, se seu aplicativo OIDC tiver quatro clientes com cliente, IDs como 0A1S2D, 1F4G9H, 1J6L4B, 6 MG, para validar somente os três primeiros clientes, você colocaria 1F4G9H\$11J6L4B\$16 GS5 MG no campo ID do cliente. IDs GS5

Se uma API estiver configurada com vários tipos de autorização, AWS AppSync valida o emissor (declaração iss) presente no token JWT a partir dos cabeçalhos da solicitação comparando-o com o URL do emissor especificado na configuração da API. No entanto, quando uma API é configurada somente com OPENID\$1CONNECT autorização, AWS AppSync ignora essa etapa de validação do URL do emissor.

## AMAZON\$1COGNITO\$1USER\$1POOLS autorização
<a name="amazon-cognito-user-pools-authorization"></a>

Esse tipo de autorização impõe tokens do OIDC fornecidos por grupos de usuários do Amazon Cognito. Seu aplicativo pode aproveitar os usuários e grupos em seus grupos de usuários e grupos de usuários de outra AWS conta e associá-los aos campos do GraphQL para controlar o acesso.

Ao usar grupos de usuários do Amazon Cognito, crie grupos aos quais os usuários pertencem. Essas informações são codificadas em um token JWT para o qual seu aplicativo envia AWS AppSync em um cabeçalho de autorização ao enviar operações do GraphQL. Use diretivas do GraphQL no esquema para controlar quais grupos podem invocar quais resolvedores em um campo, oferecendo acesso mais controlado aos clientes.

Por exemplo, digamos que tenha o seguinte esquema do GraphQL:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
}
...
```

Se tiver dois grupos em grupos de usuários do Amazon Cognito (blogueiros e leitores) e quiser restringir os leitores para que não possam adicionar novas entradas, o seu esquema deve ser semelhante ao seguinte:

```
schema {
   query: Query
   mutation: Mutation
}
```

```
type Query {
   posts:[Post!]!
   @aws_auth(cognito_groups: ["Bloggers", "Readers"])
}

type Mutation {
   addPost(id:ID!, title:String!):Post!
   @aws_auth(cognito_groups: ["Bloggers"])
}
...
```

Observe que você pode omitir a `@aws_auth` diretiva se quiser usar como padrão uma grant-or-deny estratégia específica de acesso. Você pode especificar a grant-or-deny estratégia na configuração do grupo de usuários ao criar sua API GraphQL por meio do console ou do seguinte comando da CLI:

```
$ aws appsync --region us-west-2 create-graphql-api --authentication-type AMAZON_COGNITO_USER_POOLS  --name userpoolstest --user-pool-config '{ "userPoolId":"test", "defaultEffect":"ALLOW", "awsRegion":"us-west-2"}'
```

## Usar modos de autorização adicionais
<a name="using-additional-authorization-modes"></a>

Ao adicionar outros modos de autorização, você pode definir diretamente a configuração de autorização no nível da API AWS AppSync GraphQL (ou seja, o `authenticationType` campo que você pode configurar diretamente no `GraphqlApi` objeto) e ela atua como padrão no esquema. Isso significa que qualquer tipo que não tenha uma diretiva específica deve passar na configuração de autorização no nível da API.

No nível do esquema, é possível especificar modos de autorização adicionais usando diretivas no esquema. Você pode especificar modos de autorização em campos individuais no esquema. Por exemplo, para autorização `API_KEY`, você usaria `@aws_api_key` em definições/campos de tipo de objeto de esquema. As seguintes diretivas são compatíveis com campos de esquema e definições de tipo de objeto:
+  `@aws_api_key` – para especificar que o campo é `API_KEY` autorizado.
+  `@aws_iam` – para especificar que o campo é `AWS_IAM` autorizado.
+  `@aws_oidc` – para especificar que o campo é `OPENID_CONNECT` autorizado.
+  `@aws_cognito_user_pools` – para especificar que o campo é `AMAZON_COGNITO_USER_POOLS` autorizado.
+  `@aws_lambda` – para especificar que o campo é `AWS_LAMBDA` autorizado.

Não é possível usar a diretiva `@aws_auth` junto com modos de autorização adicionais. O `@aws_auth` funciona apenas no contexto de autorização `AMAZON_COGNITO_USER_POOLS` sem modos de autorização adicionais. No entanto, é possível usar a diretiva `@aws_cognito_user_pools` no lugar da diretiva `@aws_auth`, usando os mesmos argumentos. A principal diferença entre as duas é que você pode especificar `@aws_cognito_user_pools` em qualquer definição de campo e tipo de objeto.

Para entender como os modos de autorização adicionais funcionam e como eles podem ser especificados em um esquema, vamos dar uma olhada no seguinte esquema:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   getPost(id: ID): Post
   getAllPosts(): [Post]
   @aws_api_key
}

type Mutation {
   addPost(
      id: ID!
      author: String!
      title: String!
      content: String!
      url: String!
   ): Post!
}

type Post @aws_api_key @aws_iam {
   id: ID!
   author: String
   title: String
   content: String
   url: String
   ups: Int!
   downs: Int!
   version: Int!
}
...
```

Para esse esquema, suponha que `AWS_IAM` seja o tipo de autorização padrão na API AWS AppSync GraphQL. Isso significa que os campos que não têm uma diretiva são protegidos usando o `AWS_IAM`. Por exemplo, esse é o caso do campo `getPost` no tipo `Query`. As diretivas de esquema permitem que você use mais de um modo de autorização. Por exemplo, você pode ter `API_KEY` configurado como um modo de autorização adicional na API AWS AppSync GraphQL e pode marcar um campo usando a `@aws_api_key` diretiva (por exemplo, `getAllPosts` neste exemplo). As diretivas funcionam no nível do campo, portanto, também é necessário conceder a `API_KEY` acesso ao tipo `Post`. Você pode fazer isso marcando cada campo no tipo `Post` com uma diretiva ou marcando o tipo `Post` com a diretiva `@aws_api_key`.

Para restringir ainda mais o acesso aos campos no tipo `Post`, é possível usar diretivas em relação a campos individuais no tipo `Post`, conforme mostrado a seguir.

Por exemplo, é possível adicionar um campo `restrictedContent` ao tipo `Post` e restringir o acesso a ele usando a diretiva `@aws_iam`. As solicitações `AWS_IAM` autenticadas podem acessar `restrictedContent`, no entanto, as solicitações `API_KEY` não podem acessá-lo.

```
type Post @aws_api_key @aws_iam{
   id: ID!
   author: String
   title: String
   content: String
   url: String
   ups: Int!
   downs: Int!
   version: Int!
   restrictedContent: String!
   @aws_iam
}
...
```

## Controle de acesso refinado
<a name="fine-grained-access-control"></a>

As informações anteriores demonstram como restringir ou conceder acesso a determinados campos do GraphQL. Se deseja definir controles de acesso nos dados com base em determinadas condições (por exemplo, com base no usuário que está fazendo uma chamada e se o usuário é proprietário dos dados), você pode usar modelos de mapeamento nos resolvedores. Também é possível executar lógica de negócios mais complexa, descrita em [Filtrar informações](#aws-appsync-filtering-information).

Essa seção mostra como definir controles de acesso nos dados usando um modelo de mapeamento de resolvedor do DynamoDB.

Antes de prosseguir, se você não estiver familiarizado com os modelos de mapeamento em AWS AppSync, talvez queira revisar a referência do modelo de mapeamento do [Resolver e a referência do modelo de mapeamento](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference) do [Resolver para o DynamoDB](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb).

No exemplo a seguir que usa o DynamoDB, suponha que você esteja usando o esquema de publicação de blog anterior e somente usuários que criaram uma publicação possam editá-lo. O processo de avaliação seria o usuário obter credenciais no seu aplicativo, usando Grupos de usuários do Amazon Cognito por exemplo e, em seguida, enviar essas credenciais como parte de uma operação do GraphQL. Em seguida, o modelo de mapeamento substituirá um valor das credenciais (como o nome do usuário) em uma instrução condicional que então será comparado a um valor do banco de dados.

![\[Diagram showing authentication flow from user login to database operation using Serviços da AWS.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/FGAC.png)


Para adicionar essa funcionalidade, adicione um campo do GraphQL `editPost` da seguinte forma:

```
schema {
   query: Query
   mutation: Mutation
}

type Query {
   posts:[Post!]!
}

type Mutation {
   editPost(id:ID!, title:String, content:String):Post
   addPost(id:ID!, title:String!):Post!
}
...
```

O modelo de mapeamento do resolvedor `editPost` (mostrado em um exemplo no final dessa seção) precisa executar uma verificação lógica no armazenamento de dados para permitir que apenas o usuário que criou uma publicação possa editá-la. Como essa é uma operação de edição, ela corresponde a um `UpdateItem` no DynamoDB. Execute uma verificação condicional antes de executar essa ação, usando o contexto enviado para a validação de identidade do usuário. Isso é armazenado em um objeto `Identity` com os seguintes valores:

```
{
   "accountId" : "12321434323",
   "cognitoIdentityPoolId" : "",
   "cognitoIdentityId" : "",
   "sourceIP" : "",
   "caller" : "ThisistheprincipalARN",
   "username" : "username",
   "userArn" : "Sameasabove"
}
```

Para usar esse objeto em uma chamada do `UpdateItem` do DynamoDB, é necessário armazenar as informações sobre a identidade do usuário na tabela para comparação. Primeiro, a mutação `addPost` precisa armazenar o criador. Em segundo lugar, a mutação `editPost` precisa executar a verificação condicional antes de atualizar.

Veja aqui um exemplo de código de resolvedor para `addPost` que armazena a identidade do usuário como uma coluna `Author`:

```
import { util, Context } from '@aws-appsync/utils';
import { put } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	const { id: postId, ...item } = ctx.args;
	return put({
		key: { postId },
		item: { ...item, Author: ctx.identity.username },
		condition: { postId: { attributeExists: false } },
	});
}

export const response = (ctx) => ctx.result;
```

Observe que o atributo `Author` é preenchido a partir do objeto `Identity`, que veio do aplicativo.

Por fim, veja um exemplo do código de resolvedor para `editPost`, que atualizará apenas o conteúdo da publicação de blog se a solicitação vier do usuário que criou a publicação:

```
import { util, Context } from '@aws-appsync/utils';
import { put } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	const { id, ...item } = ctx.args;
	return put({
		key: { id },
		item,
		condition: { author: { contains: ctx.identity.username } },
	});
}

export const response = (ctx) => ctx.result;
```

Este exemplo usa um `PutItem` que substitui todos os valores em vez de um `UpdateItem`, mas o mesmo conceito se aplica ao bloco de declarações `condition`.

## Filtrar informações
<a name="aws-appsync-filtering-information"></a>

Pode haver casos onde não é possível controlar a resposta da fonte de dados, mas você não deseja enviar informações desnecessárias aos clientes sobre uma gravação ou leitura bem-sucedida da fonte de dados. Nesses casos, você pode filtrar as informações usando um modelo de mapeamento de resposta.

Por exemplo, suponha que você não tenha um índice apropriado na tabela do DynamoDB da publicação de blog (como um índice em `Author`). É possível usar o seguinte resolvedor:

```
import { util, Context } from '@aws-appsync/utils';
import { get } from '@aws-appsync/utils/dynamodb';

export function request(ctx) {
	return get({ key: { ctx.args.id } });
}

export function response(ctx) {
	if (ctx.result.author === ctx.identity.username) {
		return ctx.result;
	}
	return null;
}
```

O manipulador de solicitações busca o item mesmo que o chamador não seja o autor que criou a publicação. Para evitar que isso exiba todos os dados, o manipulador de respostas verifica se o chamador corresponde ao autor do item. Se o chamador não corresponder a essa verificação, apenas uma resposta nula é retornada.

## Acesso à fonte de dados
<a name="data-source-access"></a>

AWS AppSync se comunica com fontes de dados usando funções e políticas de acesso do Identity and Access Management ([IAM](https://aws.amazon.com/iam/)). Se você estiver usando uma função existente, uma Política de Confiança precisará ser adicionada AWS AppSync para que você possa assumir a função. A relação de confiança terá a seguinte aparência:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

------

É importante restringir a política de acesso no perfil para ter permissões apenas para atuar sobre o conjunto mínimo de recursos necessários. Ao usar o AppSync console para criar uma fonte de dados e criar uma função, isso é feito automaticamente para você. No entanto, ao usar um modelo de exemplo integrado do console do IAM para criar uma função fora do console do AWS AppSync, as permissões não serão restringidas automaticamente em um recurso e você deve executar essa ação antes de mover o aplicativo para produção.

# Casos de uso de controle de acesso para proteger solicitações e respostas
<a name="security-authorization-use-cases"></a>

Na seção [Segurança](security-authz.md#aws-appsync-security) você aprendeu sobre os diferentes modos de Autorização para proteger sua API e uma introdução foi dada sobre mecanismos de Autorização refinada para entender os conceitos e o fluxo. Como AWS AppSync permite que você execute operações lógicas completas nos dados por meio do uso dos [modelos de mapeamento](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview) do GraphQL Resolver, você pode proteger os dados na leitura ou gravação de uma maneira muito flexível usando uma combinação de identidade de usuário, condicionais e injeção de dados.

Se você não estiver familiarizado com a edição de AWS AppSync resolvedores, consulte o [guia de programação](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide).

## Visão geral do
<a name="overview"></a>

Conceder acesso aos dados em um sistema é tradicionalmente feito por meio de uma [Matriz de controle do acesso](https://en.wikipedia.org/wiki/Access_Control_Matrix) em que a interseção de uma linha (recurso) e uma coluna (usuário/função) são as permissões concedidas.

AWS AppSync usa recursos em sua própria conta e insere informações de identidade (usuário/função) na solicitação e resposta do GraphQL como um [objeto de contexto](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference), que você pode usar no resolvedor. Isso significa que as permissões podem ser concedidas adequadamente em operações de leitura ou gravação com base na lógica do resolvedor. Se essa lógica estiver no nível do recurso, por exemplo, somente determinados usuários ou grupos nomeados podem read/write acessar uma linha específica do banco de dados, esses “metadados de autorização” deverão ser armazenados. AWS AppSync não armazena nenhum dado, portanto, você deve armazenar esses metadados de autorização com os recursos para que as permissões possam ser calculadas. Os metadados de autorização geralmente são um atributo (coluna) em uma tabela do DynamoDB, como um **proprietário** ou lista de usuários/grupos. Por exemplo, pode haver atributos **Leitores** e **Gravadores**.

Em um alto nível, isso significa que, se estiver lendo um item individual de uma fonte de dados, execute uma instrução `#if () ... #end` condicional no modelo da resposta depois que o resolvedor leu a fonte de dados. A verificação normalmente usará valores de usuário ou grupo em `$context.identity` para verificações de associação nos metadados de autorização retornados de uma operação de leitura. Para vários registros, como listas retornadas de uma tabela `Scan` ou `Query`, você enviará a verificação de condição como parte da operação à fonte de dados usando valores de usuário ou grupo semelhantes.

De maneira semelhante à gravação de dados você aplicará uma instrução condicional para a ação (como `PutItem` ou `UpdateItem`) para ver se o usuário ou grupo que faz uma mutação tem permissão. Novamente, o condicional muitas vezes usará um valor em `$context.identity` para comparar nos metadados de autorização daquele recurso. Para ambos os modelos da solicitação e da resposta, você também pode usar cabeçalhos personalizados de clientes para executar verificações de validação.

## Leitura de dados
<a name="reading-data"></a>

Conforme descrito acima, os metadados de autorização para realizar uma verificação devem ser armazenados com um recurso ou enviados para a solicitação do GraphQL (identidade, cabeçalho, etc.). Para demonstrar isso suponha que você tem a tabela do DynamoDB abaixo:

![\[DynamoDB table with ID, Data, PeopleCanAccess, GroupsCanAccess, and Owner columns.\]](http://docs.aws.amazon.com/pt_br/appsync/latest/devguide/images/auth.png)


A chave primária é `id` e os dados a serem acessados são `Data`. As outras colunas são exemplos de verificações que podem ser executadas para autorização. `Owner` seria uma `String` enquanto `PeopleCanAccess` e `GroupsCanAccess` seriam `String Sets`, conforme descrito na [Referência do modelo de mapeamento do resolvedor para o DynamoDB](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb).

Na [visão geral do modelo de mapeamento do resolvedor](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview) o diagrama mostra como o modelo da resposta contém não apenas o objeto de contexto, mas também os resultados da fonte de dados. Para consultas do GraphQL de itens individuais, você pode usar o modelo da resposta para verificar se o usuário tem permissão para ver esses resultados ou retornar uma mensagem de erro de autorização. Isso geralmente é indicado como um "Filtro de autorização". Para consultas do GraphQL que retornam listas, usando uma Scan ou Query, é mais eficiente realizar a verificação no modelo da solicitação e retornar dados somente se uma condição de autorização for atendida. A implementação é:

1. GetItem - verificação de autorização para registros individuais. Feita usando instruções `#if() ... #end`.

1. Operações Scan/Query – verificação de autorização é uma instrução `"filter":{"expression":...}`. As verificações comuns são a igualdade (`attribute = :input`) ou verificar se um valor está em uma lista (`contains(attribute, :input)`).

Em \$12 o `attribute` em ambas as instruções representa o nome da coluna do registro em uma tabela, como `Owner` no exemplo acima. Você pode transformar isso em alias com um sinal `#` e usar `"expressionNames":{...}`, mas não é obrigatório. O `:input` é uma referência ao valor que você está comparando com o atributo do banco de dados, que será definido em `"expressionValues":{...}`. Você verá esses exemplos abaixo.

### Caso de uso: o proprietário pode fazer leitura
<a name="use-case-owner-can-read"></a>

Usando a tabela acima, se apenas deseja retornar dados se `Owner == Nadia` para uma única operação de leitura (`GetItem`) o modelo terá a seguinte aparência:

```
#if($context.result["Owner"] == $context.identity.username)
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end
```

Algumas coisas devem ser mencionadas aqui, que serão reutilizadas nas seções restantes. Primeiro, a verificação usa `$context.identity.username` que será o nome de login de usuário amigável se grupos de usuários do Amazon Cognito for usado e será a identidade do usuário se o IAM for usado (incluindo as Identidades federadas do Amazon Cognito). Existem outros valores a serem armazenados para um proprietário, como o valor exclusivo "identidade do Amazon Cognito", que é útil ao federar logins de vários locais, e você deve revisar as opções disponíveis na [Referência de contexto do modelo de mapeamento do resolvedor](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference).

Segundo, a verificação condicional else respondendo com `$util.unauthorized()` é totalmente opcional, mas recomendado como uma das melhores práticas ao projetar sua API GraphQL.

### Caso de uso: codificar acesso específico
<a name="use-case-hardcode-specific-access"></a>

```
// This checks if the user is part of the Admin group and makes the call
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #if($group == "Admin")
        #set($inCognitoGroup = true)
    #end
#end
#if($inCognitoGroup)
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "attributeValues" : {
        "owner" : $util.dynamodb.toDynamoDBJson($context.identity.username)
        #foreach( $entry in $context.arguments.entrySet() )
            ,"${entry.key}" : $util.dynamodb.toDynamoDBJson($entry.value)
        #end
    }
}
#else
    $utils.unauthorized()
#end
```

### Caso de uso: filtrar uma lista de resultados
<a name="use-case-filtering-a-list-of-results"></a>

No exemplo anterior você pôde executar uma verificação em `$context.result` diretamente pois retornou um único item, no entanto algumas operações como uma verificação retornarão vários itens em `$context.result.items`, onde será necessário executar o filtro de autorização e retornar apenas os resultados que o usuário tem permissão para ver. Digamos que o campo `Owner` tinha o IdentityID do Amazon Cognito dessa vez definido no registro, então você poderia usar o seguinte modelo de mapeamento da resposta para filtrar a exibição somente dos registros de propriedade do usuário:

```
#set($myResults = [])
#foreach($item in $context.result.items)
    ##For userpools use $context.identity.username instead
    #if($item.Owner == $context.identity.cognitoIdentityId)
        #set($added = $myResults.add($item))
    #end
#end
$utils.toJson($myResults)
```

### Caso de uso: várias pessoas podem fazer leitura
<a name="use-case-multiple-people-can-read"></a>

Outra opção de autorização popular é permitir que um grupo de pessoas seja capaz de ler dados. No exemplo abaixo, o `"filter":{"expression":...}` retorna apenas valores de uma verificação de tabela se o usuário que executa a consulta do GraphQL estiver listado no conjunto de `PeopleCanAccess`.

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": #if(${context.arguments.count}) $util.toJson($context.arguments.count) #else 20 #end,
    "nextToken": #if(${context.arguments.nextToken})  $util.toJson($context.arguments.nextToken) #else null #end,
    "filter":{
        "expression": "contains(#peopleCanAccess, :value)",
        "expressionNames": {
                "#peopleCanAccess": "peopleCanAccess"
        },
        "expressionValues": {
                ":value": $util.dynamodb.toDynamoDBJson($context.identity.username)
        }
    }
}
```

### Caso de uso: o grupo pode fazer leitura
<a name="use-case-group-can-read"></a>

Semelhante ao último caso de uso, pode ser que apenas as pessoas em um ou mais grupos tenham direitos para ler determinados itens em um banco de dados. O uso da operação `"expression": "contains()"` é semelhante, no entanto é um OU lógico de todos os grupos dos quais um usuário pode fazer parte, o que precisa ser considerado na associação definida. Nesse caso, acumulamos uma instrução `$expression` abaixo para cada grupo em que o usuário está e, em seguida, enviamos isso ao filtro:

```
#set($expression = "")
#set($expressionValues = {})
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
    #set( $val = {})
    #set( $test = $val.put("S", $group))
    #set( $values = $expressionValues.put(":var$foreach.count", $val))
    #if ( $foreach.hasNext )
    #set( $expression = "${expression} OR" )
    #end
#end
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": #if(${context.arguments.count}) $util.toJson($context.arguments.count) #else 20 #end,
    "nextToken": #if(${context.arguments.nextToken})  $util.toJson($context.arguments.nextToken) #else null #end,
    "filter":{
        "expression": "$expression",
        "expressionValues": $utils.toJson($expressionValues)
    }
}
```

## Gravação de dados
<a name="writing-data"></a>

A gravação de dados em mutações sempre é controlada no modelo de mapeamento da solicitação. No caso de fontes de dados do DynamoDB, a chave é usar um `"condition":{"expression"...}"` adequado que executa a validação nos metadados de autorização nessa tabela. Em [Segurança](security-authz.md#aws-appsync-security), fornecemos um exemplo que pode ser usado para verificar o campo `Author` em uma tabela. Os casos de uso nessa seção exploram mais casos de uso.

### Caso de uso: vários proprietários
<a name="use-case-multiple-owners"></a>

Usando a tabela de exemplo do diagrama anterior, suponha que a lista `PeopleCanAccess`

```
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "update" : {
        "expression" : "SET meta = :meta",
        "expressionValues": {
            ":meta" : $util.dynamodb.toDynamoDBJson($ctx.args.meta)
        }
    },
    "condition" : {
        "expression"       : "contains(Owner,:expectedOwner)",
        "expressionValues" : {
            ":expectedOwner" : $util.dynamodb.toDynamoDBJson($context.identity.username)
        }
    }
}
```

### Caso de uso: o grupo pode criar um novo registro
<a name="use-case-group-can-create-new-record"></a>

```
#set($expression = "")
#set($expressionValues = {})
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
    #set( $val = {})
    #set( $test = $val.put("S", $group))
    #set( $values = $expressionValues.put(":var$foreach.count", $val))
    #if ( $foreach.hasNext )
    #set( $expression = "${expression} OR" )
    #end
#end
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        ## If your table's hash key is not named 'id', update it here. **
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
        ## If your table has a sort key, add it as an item here. **
    },
    "attributeValues" : {
        ## Add an item for each field you would like to store to Amazon DynamoDB. **
        "title" : $util.dynamodb.toDynamoDBJson($ctx.args.title),
        "content": $util.dynamodb.toDynamoDBJson($ctx.args.content),
        "owner": $util.dynamodb.toDynamoDBJson($context.identity.username)
    },
    "condition" : {
        "expression": $util.toJson("attribute_not_exists(id) AND $expression"),
        "expressionValues": $utils.toJson($expressionValues)
    }
}
```

### Caso de uso: o grupo pode atualizar um registro existente
<a name="use-case-group-can-update-existing-record"></a>

```
#set($expression = "")
#set($expressionValues = {})
#foreach($group in $context.identity.claims.get("cognito:groups"))
    #set( $expression = "${expression} contains(groupsCanAccess, :var$foreach.count )" )
    #set( $val = {})
    #set( $test = $val.put("S", $group))
    #set( $values = $expressionValues.put(":var$foreach.count", $val))
    #if ( $foreach.hasNext )
    #set( $expression = "${expression} OR" )
    #end
#end
{
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "update":{
                "expression" : "SET title = :title, content = :content",
        "expressionValues": {
            ":title" : $util.dynamodb.toDynamoDBJson($ctx.args.title),
            ":content" : $util.dynamodb.toDynamoDBJson($ctx.args.content)
        }
    },
    "condition" : {
        "expression": $util.toJson($expression),
        "expressionValues": $utils.toJson($expressionValues)
    }
}
```

## Registros públicos e privados
<a name="public-and-private-records"></a>

Com os filtros condicionais você também pode optar por marcar os dados como privado, público ou alguma outra verificação Booliana. Isso pode ser combinado como parte de um filtro de autorização dentro do modelo da resposta. Usar essa verificação é uma boa maneira de ocultar temporariamente os dados ou removê-los da visualização sem tentar controlar a associação de grupo.

Por exemplo, suponha que você adicionou um atributo em cada item na tabela do DynamoDB chamada `public` com um valor de `yes` ou `no`. O seguinte modelo da resposta pode ser usado em uma chamada `GetItem` para exibir os dados somente se o usuário estiver em um grupo que tem acesso E se esses dados estiverem marcados como público:

```
#set($permissions = $context.result.GroupsCanAccess)
#set($claimPermissions = $context.identity.claims.get("cognito:groups"))

#foreach($per in $permissions)
    #foreach($cgroups in $claimPermissions)
        #if($cgroups == $per)
            #set($hasPermission = true)
        #end
    #end
#end

#if($hasPermission && $context.result.public == 'yes')
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end
```

O código acima também pode usar um OU lógico (`||`) para permitir que as pessoas façam leitura se tiverem permissão para um registro ou se for público:

```
#if($hasPermission || $context.result.public == 'yes')
    $utils.toJson($context.result)
#else
    $utils.unauthorized()
#end
```

No geral, os operadores padrão `==`, `!=`, `&&` e `||` serão úteis ao executar verificações de autorização.

## Dados em tempo real
<a name="security-real-time-data"></a>

Você pode aplicar Controles de acesso refinados em assinaturas do GraphQL no momento em que um cliente faz uma assinatura, usando as mesmas técnicas descritas anteriormente nessa documentação. Anexe um resolvedor ao campo de assinatura, no momento em que pode consultar dados de uma fonte de dados e realizar a lógica condicional nos modelos de mapeamento da solicitação ou da resposta. Você também pode retornar dados adicionais para o cliente, como os resultados iniciais de uma assinatura, desde que a estrutura de dados corresponda àquela do tipo retornado na assinatura do GraphQL.

### Caso de uso: o usuário pode assinar apenas conversas específicas
<a name="use-case-user-can-subscribe-to-specific-conversations-only"></a>

Um caso de uso comum para dados em tempo real com assinaturas do GraphQL é a criação de um aplicativo mensagens ou bate-papo privado. Ao criar um aplicativo de bate-papo com vários usuários, as conversas podem ocorrer entre duas pessoas ou entre várias pessoas. Elas podem ser agrupadas em "salas", privadas ou públicas. Dessa forma, você deseja autorizar apenas um usuário para assinar uma conversa (que pode ser um a um ou entre um grupo) à qual terão o acesso concedido. Para fins de demonstração, o exemplo abaixo mostra um caso de uso simples de um usuário que envia uma mensagem privada para outro. A configuração tem duas tabelas do Amazon DynamoDB:
+ Tabela de mensagens: (chave primária) `toUser`, (chave de classificação) `id` 
+ Tabela de permissões: (chave primária) `username` 

A tabela de Mensagens armazena as mensagens que realmente foram enviadas por meio de uma mutação do GraphQL. A tabela de Permissões é verificada pela assinatura do GraphQL para autorização no momento da conexão do cliente. O exemplo abaixo pressupõe que você está usando o seguinte esquema do GraphQL:

```
input CreateUserPermissionsInput {
    user: String!
    isAuthorizedForSubscriptions: Boolean
}

type Message {
    id: ID
    toUser: String
    fromUser: String
    content: String
}

type MessageConnection {
    items: [Message]
    nextToken: String
}

type Mutation {
    sendMessage(toUser: String!, content: String!): Message
    createUserPermissions(input: CreateUserPermissionsInput!): UserPermissions
    updateUserPermissions(input: UpdateUserPermissionInput!): UserPermissions
}

type Query {
    getMyMessages(first: Int, after: String): MessageConnection
    getUserPermissions(user: String!): UserPermissions
}

type Subscription {
    newMessage(toUser: String!): Message
        @aws_subscribe(mutations: ["sendMessage"])
}

input UpdateUserPermissionInput {
    user: String!
    isAuthorizedForSubscriptions: Boolean
}

type UserPermissions {
    user: String
    isAuthorizedForSubscriptions: Boolean
}

schema {
    query: Query
    mutation: Mutation
    subscription: Subscription
}
```

Algumas das operações padrão, como `createUserPermissions()`, não são abordadas abaixo para ilustrar os resolvedores de assinatura, mas são implementações padrão de resolvedores do DynamoDB. Em vez disso, vamos nos concentrar nos fluxos de autorização da assinatura com resolvedores. Para enviar uma mensagem de um usuário para outro, anexe um resolvedor ao campo `sendMessage()` e selecione a fonte de dados da tabela de **Mensagens** com o seguinte modelo da solicitação:

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "toUser" : $util.dynamodb.toDynamoDBJson($ctx.args.toUser),
        "id" : $util.dynamodb.toDynamoDBJson($util.autoId())
    },
    "attributeValues" : {
        "fromUser" : $util.dynamodb.toDynamoDBJson($context.identity.username),
        "content" : $util.dynamodb.toDynamoDBJson($ctx.args.content),
    }
}
```

Neste exemplo, usamos `$context.identity.username`. Isso retorna as informações do usuário AWS Identity and Access Management ou dos usuários do Amazon Cognito. O modelo da resposta é uma simples passagem de `$util.toJson($ctx.result)`. Salvar e voltar à página do esquema. Em seguida, anexe um resolvedor para a assinatura `newMessage()`, usando a tabela de **Permissões** como uma fonte de dados e o seguinte modelo de mapeamento da solicitação:

```
{
    "version": "2018-05-29",
    "operation": "GetItem",
    "key": {
        "username": $util.dynamodb.toDynamoDBJson($ctx.identity.username),
    },
}
```

Em seguida, use o seguinte modelo de mapeamento da resposta para executar as verificações de autorização usando os dados da tabela de **Permissões**:

```
#if(! ${context.result})
    $utils.unauthorized()
#elseif(${context.identity.username} != ${context.arguments.toUser})
    $utils.unauthorized()
#elseif(! ${context.result.isAuthorizedForSubscriptions})
    $utils.unauthorized()
#else
##User is authorized, but we return null to continue
    null
#end
```

Nesse caso, você está fazendo três verificações de autorização. A primeira garante que um resultado seja retornado. A segunda garante que o usuário não esteja assinando mensagens destinadas a outra pessoa. A terceira garante que o usuário tenha permissão para assinar qualquer campo, verificando um atributo do DynamoDB de `isAuthorizedForSubscriptions` armazenado como um `BOOL`.

Para testar as coisas, você pode entrar no AWS AppSync console usando grupos de usuários do Amazon Cognito e um usuário chamado “Nadia” e, em seguida, executar a seguinte assinatura do GraphQL:

```
subscription AuthorizedSubscription {
    newMessage(toUser: "Nadia") {
        id
        toUser
        fromUser
        content
    }
}
```

Se, na tabela de **Permissões**, houver um registro para o atributo chave `username` de `Nadia` com `isAuthorizedForSubscriptions` definido como `true`, você verá uma resposta bem-sucedida. Se tentar um `username` diferente na consulta `newMessage()` acima, um erro será retornado.

# Usando AWS WAF para proteger seu AWS AppSync APIs
<a name="WAF-Integration"></a>

AWS WAF é um firewall de aplicativos da web que ajuda a proteger os aplicativos da web e APIs contra ataques. Isso permite configurar um conjunto de regras chamado de lista de controle de acesso à web (ACL da web) que permitem, bloqueiam ou monitoram (contam) solicitações da web com base em regras e condições de segurança da web personalizáveis que você define. Ao integrar sua AWS AppSync API AWS WAF, você ganha mais controle e visibilidade do tráfego HTTP aceito pela sua API. Para saber mais AWS WAF, consulte [Como AWS WAF funciona](https://docs.aws.amazon.com/waf/latest/developerguide/how-aws-waf-works.html) no Guia do AWS WAF desenvolvedor. 

Você pode usar AWS WAF para proteger sua AppSync API contra explorações comuns da Web, como injeção de SQL e ataques de script entre sites (XSS). Isso pode afetar a disponibilidade e a performance da API, comprometer a segurança ou consumir recursos excessivos. Por exemplo, você pode criar regras para permitir ou bloquear solicitações de intervalos de endereços IP especificados, solicitações de blocos CIDR, solicitações originárias de um país ou região específico, solicitações que contenham código SQL mal-intencionado ou solicitações que contenham script mal-intencionado.

Você também pode criar regras que correspondam a uma string especificada ou um padrão de expressão regular em cabeçalhos HTTP, método, URI, string de consulta e o corpo da solicitação (limitados aos primeiros 8 KB). Além disso, você pode criar regras para bloquear ataques de agentes de usuário específicos, bad bots e descarte de conteúdo. Por exemplo, podem ser utilizadas regras baseadas em intervalos para especificar o número de solicitações da web que são permitidas por cada IP do cliente no final de um período de cinco minutos em atualização contínua.

Para saber mais sobre os tipos de regras compatíveis e os AWS WAF recursos adicionais, consulte o [Guia do AWS WAF desenvolvedor](https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html) e a [Referência da AWS WAF API](https://docs.aws.amazon.com/waf/latest/APIReference/API_Types_AWS_WAFV2.html).

**Importante**  
AWS WAF é sua primeira linha de defesa contra explorações na web. Quando AWS WAF ativado em uma API, AWS WAF as regras são avaliadas antes de outros recursos de controle de acesso, como autorização de chave de API, políticas do IAM, tokens OIDC e grupos de usuários do Amazon Cognito. 

## Integre uma AppSync API com AWS WAF
<a name="integrate-API-with-WAF"></a>

Você pode integrar uma API do Appsync AWS WAF usando o Console de gerenciamento da AWS, o AWS CLI AWS CloudFormation, ou qualquer outro cliente compatível.

**Para integrar uma AWS AppSync API com AWS WAF**

1. Crie uma ACL AWS WAF da web. Para obter etapas detalhadas sobre o uso da [Console do AWS WAF](https://console.aws.amazon.com/waf/), consulte [Criar uma ACL da Web](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-creating.html).

1. Defina as regras para a ACL da Web. Uma regra ou regras são definidas no processo de criação da ACL da Web. Para obter informações sobre como estruturar regras, consulte [Regras do AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rules.html). Para ver exemplos de regras úteis que você pode definir para sua AWS AppSync API, consulte[Criar regras para uma ACL da Web](#Creating-web-acl-rules).

1. Associe a ACL da web a uma AWS AppSync API. Você pode executar essa etapa no [AWS WAF console](https://console.aws.amazon.com/wafv2/) ou no [AppSync console](https://console.aws.amazon.com/appsync/). 
   + Para associar a ACL da web a uma AWS AppSync API no AWS WAF console, siga as instruções para [associar ou desassociar uma ACL da Web a um AWS recurso no Guia](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-associating-aws-resource.html) do desenvolvedor. AWS WAF 
   + Para associar a ACL da web a uma AWS AppSync API no console AWS AppSync 

     1. Faça login no Console de gerenciamento da AWS e abra o [AppSync console](https://console.aws.amazon.com/appsync/).

     1. Escolha a API que deseja associar a uma ACL da Web.

     1. No painel de navegação, selecione **configurações**.

     1. Na seção **Firewall da aplicação web**, ative **Habilitar AWS WAF**.

     1. Na lista suspensa **ACL da Web**, escolha o nome da ACL da Web para associar à sua API.

     1. Escolha **Salvar** para associar a ACL da Web à sua API.

   

**nota**  
Depois de criar uma ACL da web no AWS WAF console, pode levar alguns minutos para que a nova ACL da web esteja disponível. Se você não vir uma ACL da Web recém-criada no **Firewall de aplicativo web**, aguarde alguns minutos e repita as etapas para associar a ACL da Web à sua API.

**nota**  
AWS WAF a integração só suporta o `Subscription registration message` evento para endpoints em tempo real. AWS AppSync responderá com uma mensagem de erro em vez de uma `start_ack` mensagem para qualquer mensagem `Subscription registration message` bloqueada por AWS WAF. 

Depois de associar uma ACL da web a uma AWS AppSync API, você gerenciará a ACL da web usando o. AWS WAF APIs Você não precisa associar novamente a ACL da web à sua AWS AppSync API, a menos que queira associar a AWS AppSync API a uma ACL da web diferente.

## Criar regras para uma ACL da Web
<a name="Creating-web-acl-rules"></a>

As regras definem como inspecionar solicitações da Web e o que fazer quando uma solicitação da Web corresponde aos critérios de inspeção. As regras não existem AWS WAF sozinhas. Você pode acessar uma regra por nome em um grupo de regras ou na ACL da Web onde ela está definida. Para obter mais informações, consulte [Regras do AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rules.html). Os exemplos a seguir demonstram como definir e associar regras que são úteis para proteger uma AppSync API.

**Example regra ACL da Web para limitar o tamanho do corpo da solicitação**  
Veja a seguir um exemplo de regra que limita o tamanho do corpo das solicitações. Isso seria inserido no **editor Rule JSON** ao criar uma ACL da web no AWS WAF console.  

```
{
    "Name": "BodySizeRule", 
    "Priority": 1, 
    "Action": {
        "Block": {}
    }, 
    "Statement": {
        "SizeConstraintStatement": {
            "ComparisonOperator": "GE",
            "FieldToMatch": {
                "Body": {}
            },
            "Size": 1024, 
            "TextTransformations": [
                {
                    "Priority": 0, 
                    "Type": "NONE"
                }
             ]
          }
       }, 
       "VisibilityConfig": {
           "CloudWatchMetricsEnabled": true, 
           "MetricName": "BodySizeRule", 
           "SampledRequestsEnabled": true
        }
}
```
Depois de criar sua ACL da web usando a regra do exemplo anterior, você deve associá-la à sua AppSync API. Como alternativa ao uso do Console de gerenciamento da AWS, você pode executar essa etapa no AWS CLI executando o comando a seguir.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```
Pode levar alguns minutos para que as alterações sejam propagadas, mas, após a execução deste comando, as solicitações que contenham um corpo maior que 1.024 bytes serão rejeitadas pelo AWS AppSync.  
Depois de criar uma nova ACL da web no AWS WAF console, pode levar alguns minutos para que a ACL da web esteja disponível para ser associada a uma API. Se você executar o comando da CLI e receber um erro `WAFUnavailableEntityException`, aguarde alguns minutos e tente executar o comando novamente.

**Example regra da ACL da Web para limitar as solicitações de um único endereço IP**  
Veja a seguir um exemplo de uma regra que limita uma AppSync API a 100 solicitações de um único endereço IP. Isso seria inserido no **editor de regras JSON** ao criar uma ACL da web com uma regra baseada em taxa no console. AWS WAF   

```
{
  "Name": "Throttle",
  "Priority": 0,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "Throttle"
  },
  "Statement": {
    "RateBasedStatement": {
      "Limit": 100,
      "AggregateKeyType": "IP"
    }
  }
}
```
Depois de criar sua ACL da web usando a regra do exemplo anterior, você deve associá-la à sua AppSync API. Você pode executar essa etapa no AWS CLI executando o comando a seguir.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```

**Example Regra ACL da Web para evitar consultas de introspecção GraphQL \$1\$1schema para uma API**  
Veja a seguir um exemplo de uma regra que impede consultas de introspecção do GraphQL \$1\$1schema em uma API. Qualquer corpo HTTP que inclua a string "\$1\$1schema" será bloqueado. Isso seria inserido no **editor Rule JSON** ao criar uma ACL da web no AWS WAF console.  

```
{
  "Name": "BodyRule",
  "Priority": 5,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "BodyRule"
  },
  "Statement": {
    "ByteMatchStatement": {
      "FieldToMatch": {
        "Body": {}
      },
      "PositionalConstraint": "CONTAINS",
      "SearchString": "__schema",
      "TextTransformations": [
        {
          "Type": "NONE",
          "Priority": 0
        }
      ]
    }
  }
}
```
Depois de criar sua ACL da web usando a regra do exemplo anterior, você deve associá-la à sua AppSync API. Você pode executar essa etapa no AWS CLI executando o comando a seguir.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```