

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Configuración de la autorización y la autenticación para proteger su GraphQL APIs
<a name="security-authz"></a>

AWS AppSync ofrece los siguientes tipos de autorización para proteger GraphQL APIs: claves de API, Lambda, IAM, OpenID Connect y Cognito User Pools. Cada opción proporciona un método de seguridad diferente: 

1. **Autorización de claves de API**: controla la limitación de los no autenticados, lo que proporciona una opción de seguridad sencilla APIs. 

1. **Autorización de Lambda**: habilita una lógica de autorización personalizada, que explica las entradas y salidas de las funciones en detalle. 

1. **Autorización de IAM**: utiliza el proceso AWS de firma de la versión 4, que permite un control de acceso detallado a través de las políticas de IAM. 

1. **Autorización de OpenID Connect**: se integra con los servicios compatibles con OIDC para la autenticación de usuarios. 

1. **Grupos de usuarios de Cognito**: implementa el control de acceso basado en grupos mediante las características de administración de usuarios de Cognito. 

## Tipos de autorización
<a name="authorization-types"></a>

Existen cinco formas de autorizar que las aplicaciones interactúen con la API de AWS AppSync GraphQL. Para especificar el tipo de autorización que va a utilizar, especifique uno de los siguientes valores de tipo de autorización en su llamada a la AWS AppSync API o CLI:
+   
** `API_KEY` **  
Para utilizar claves de API.
+   
** `AWS_LAMBDA` **  
Para usar una AWS Lambda función.
+   
** `AWS_IAM` **  
Para usar permisos AWS Identity and Access Management ([IAM](https://aws.amazon.com/iam/)).
+   
** `OPENID_CONNECT` **  
Para utilizar su proveedor de OpenID Connect.
+   
** `AMAZON_COGNITO_USER_POOLS` **  
Para utilizar con un grupo de usuarios de Amazon Cognito.

Estos tipos de autorización básicos funcionan para la mayoría de desarrolladores. Para casos de uso más avanzados, puede añadir modos de autorización adicionales mediante la consola, la CLI y AWS CloudFormation. Para modos de autorización adicionales, AWS AppSync proporciona un tipo de autorización que toma los valores enumerados anteriormente (es decir`API_KEY`,`AWS_LAMBDA`, `AWS_IAM``OPENID_CONNECT`, y`AMAZON_COGNITO_USER_POOLS`).

Al especificar `API_KEY`, `AWS_LAMBDA` o `AWS_IAM` como tipo de autorización principal o predeterminado, no puede especificarlos de nuevo como uno de los modos de autorización adicionales. Del mismo modo, no puede duplicar `API_KEY`, `AWS_LAMBDA` ni `AWS_IAM` dentro de modos de autorización adicionales. Puede utilizar diferentes proveedores de OpenID Connect y grupos de usuarios de Amazon Cognito. Sin embargo, no puede utilizar proveedores de OpenID Connect o grupos de usuarios de Amazon Cognito duplicados entre el modo de autorización predeterminado y cualquiera de los modos de autorización adicionales. Puede especificar diferentes clientes para el proveedor de OpenID Connect o el grupo de usuarios de Amazon Cognito mediante la expresión regular de configuración correspondiente.

Al guardar los cambios en la configuración de la API, AWS AppSync comienza a propagarlos. Hasta que se propague el cambio de configuración, AWS AppSync seguirá publicando el contenido de la configuración anterior. Una vez propagado el cambio de configuración, comienza AWS AppSync inmediatamente a servir el contenido en función de la nueva configuración. Mientras AWS AppSync se propagan los cambios para una API, no podemos determinar si la API está publicando el contenido en función de la configuración anterior o de la nueva.

## API\$1KEY autorización
<a name="api-key-authorization"></a>

Los no autenticados APIs requieren una regulación más estricta que los autenticados. APIs Una forma de supervisar la limitación controlada de puntos de enlace de GraphQL sin autenticar es mediante el uso de claves de API. Una clave de API es un valor de código literal en la aplicación generado por el servicio de AWS AppSync cuando se crea un punto de enlace de GraphQL sin autenticar. Puede rotar las claves de API desde la consola, desde la CLI o con la [referencia de la API de AWS AppSync](https://docs.aws.amazon.com/appsync/latest/APIReference/).

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

1. [Inicie sesión en la consola y ábrala Consola de administración de AWS . AppSync ](https://console.aws.amazon.com/appsync/)

   1. En el **APIs panel de control**, elige tu API de GraphQL.

   1. En la **barra lateral**, seleccione **Configuración.**

1. En **Modo de autorización predeterminado**, seleccione **Clave de API**.

1. En la pestaña **Claves de API**, elija **Agregar clave de API**.

   Se generará una nueva clave de API en la tabla.

   1. Para eliminar una clave de API antigua, selecciónela en la tabla y, a continuación, elija **Eliminar**.

1. Elija **Guardar** en la parte inferior de la página.

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

1. Si aún no lo ha hecho, configure el acceso a la AWS CLI. Para obtener más información, consulte [Fundamentos de configuración](https://docs.aws.amazon.com//cli/latest/userguide/cli-configure-quickstart.html).

1. Cree un objeto de API de GraphQL ejecutando el 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).

   Deberá escribir dos parámetros para este comando concreto:

   1. El `api-id` de su API de GraphQL.

   1. El nuevo `name` de su API. Puede utilizar el mismo `name`.

   1. El `authentication-type`, que será `API_KEY`.
**nota**  
Hay otros parámetros, como `Region`, que deben configurarse pero que normalmente se utilizarán de forma predeterminada en los valores de configuración de la CLI.

   Un comando de ejemplo puede tener este aspecto:

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

   Aparecerá un resultado en la CLI. A continuación se muestra un ejemplo en 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"
       }
   }
   ```

------

Las claves de API se pueden configurar con una duración de hasta 365 días que pueden ampliarse hasta otros 365 días a partir de la fecha de vencimiento. Las claves de API se recomiendan con fines de desarrollo o para casos de uso en los que es seguro exponer una API pública.

En el cliente, la clave de API se especifica mediante el encabezado `x-api-key`.

Por ejemplo, si `API_KEY` es `'ABC123'`, puede enviar una consulta de GraphQL mediante `curl`, como se indica a continuación:

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

## AWS\$1LAMBDA autorización
<a name="aws-lambda-authorization"></a>

Puede implementar su propia lógica de autorización de API mediante una AWS Lambda función. Puede usar una función de Lambda para su autorizador principal o secundario, pero solo puede haber una función de autorización de Lambda por cada API. Cuando se utilizan funciones de Lambda para la autorización, es aplicable lo siguiente:
+ Si la API tiene habilitados los modos de autorización `AWS_LAMBDA` y `AWS_IAM` , la firma SigV4 no se puede utilizar como token de autorización de `AWS_LAMBDA`.
+ Si la API tiene habilitados los modos de autorización `AWS_LAMBDA` y `OPENID_CONNECT`, o el modo de autorización `AMAZON_COGNITO_USER_POOLS` activado, el token OIDC no se puede utilizar como token de autorización de `AWS_LAMBDA`. Tenga en cuenta que el token OIDC puede ser un esquema Bearer.
+ Una función de Lambda no debe devolver más de 5 MB de datos contextuales para los solucionadores.

Por ejemplo, si su token de autorización es `'ABC123'`, puede enviar una consulta de GraphQL mediante curl, como se indica a continuación: 

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

Las funciones de Lambda se invocan antes de cada consulta o mutación. El valor devuelto se puede almacenar en caché en función del ID de la API y el token de autenticación. Cuando la respuesta de un autorizador Lambda es inferior a 1 048.576 bytes, guarda en AWS AppSync caché la respuesta para solicitudes posteriores. Si la respuesta del autorizador Lambda es igual o superior a 1 048.576 bytes, AWS AppSync no almacena en caché la respuesta e invoca al autorizador Lambda para cada solicitud entrante. Para optimizar el rendimiento y minimizar los costos de invocación de Lambda, le recomendamos que limite las respuestas del autorizador de Lambda a 1 048 576 bytes. De forma predeterminada, el almacenamiento en caché no está activado, pero se puede habilitar en la API o configurando el valor `ttlOverride` en un valor de retorno de una función. 

Si lo desea, puede especificar una expresión regular que valide los tokens de autorización antes de que se llame a la función. Estas expresiones regulares se utilizan para validar que un token de autorización tiene el formato correcto antes de llamar a la función. Cualquier solicitud que utilice un token que no coincida con esta expresión regular se rechazará automáticamente. 

Las funciones Lambda utilizadas para la autorización requieren que se `appsync.amazonaws.com` les aplique una política principal que permita AWS AppSync llamarlas. Esta acción se realiza automáticamente en la AWS AppSync consola; la AWS AppSync consola *no* elimina la política. Para obtener más información sobre cómo adjuntar políticas a las funciones de Lambda, [consulte Políticas basadas en recursos](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) en la Guía para desarrolladores. AWS Lambda 

La función de Lambda que especifique recibirá un evento con la siguiente 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
    }
}
```

El `event` objeto contiene los encabezados que se enviaron en la solicitud desde el cliente de la aplicación a. AWS AppSync

La función de autorización debe devolver, como mínimo`isAuthorized`, un booleano que indique si la solicitud está autorizada. AWS AppSync reconoce las siguientes claves devueltas por las funciones de autorización de Lambda:

**nota**  
El valor de la operación de conexión `operationName` en `requestContext` el caso de una operación de WebSocket conexión se establece en "`DeepDish:Connect`». AWS AppSync 

### Lista de funciones
<a name="aws-lambda-authorization-list"></a>

`isAuthorized` (valor booleano, obligatorio)  
Un valor booleano que indica si el valor de `authorizationToken` está autorizado a realizar llamadas a la API de GraphQL.  
Si este valor es true, la ejecución de la API de GraphQL continúa. Si este valor es false, se genera `UnauthorizedException`

`deniedFields` (lista de cadenas, opcional)  
Una lista que se cambia forzosamente a `null`, incluso si un solucionador ha devuelto un valor.  
Cada elemento es un ARN de campo totalmente cualificado en forma de `arn:aws:appsync:us-east-1:111122223333:apis/GraphQLApiId/types/TypeName/fields/FieldName` o una forma abreviada de `TypeName.FieldName`. Se debe usar el formulario ARN completo cuando dos personas APIs comparten un autorizador de funciones Lambda y puede haber ambigüedad entre los tipos y campos comunes entre ambos. APIs

`resolverContext` (objeto JSON, opcional)  
Un objeto JSON visible como `$ctx.identity.resolverContext` en las plantillas de solucionadores. Por ejemplo, si un solucionador devuelve la estructura siguiente:  

```
{
  "isAuthorized":true
  "resolverContext": {
    "banana":"very yellow",
    "apple":"very green" 
  }
}
```
El valor de `ctx.identity.resolverContext.apple` en las plantillas de solucionador será "`very green`". El objeto `resolverContext` solo admite pares clave-valor. No se admiten las claves anidadas.  
El tamaño total de este objeto JSON no debe superar los 5 MB.

`ttlOverride` (entero, opcional)  
El número de segundos durante los que se debe almacenar una respuesta en caché. Si no se devuelve ningún valor, se utiliza el valor de la API. Si es 0, la respuesta no se almacena en caché.

Los autorizadores Lambda tienen un tiempo de espera estándar de 10 segundos, pero pueden agotarse antes en condiciones de tráfico máximo. Recomendamos diseñar funciones para que se ejecuten en el menor tiempo posible (menos de 1 segundo) a fin de escalar el rendimiento de la API.

Varias AWS AppSync APIs pueden compartir una sola función Lambda de autenticación. No se permite el uso de autorizadores entre cuentas.

Al compartir una función de autorización entre varias APIs, tenga en cuenta que los nombres de campo abreviados (`typename.fieldname`) pueden ocultar campos de forma inadvertida. Para eliminar la ambigüedad de un campo en `deniedFields`, puede especificar un ARN de campo inequívoco en forma de `arn:aws:appsync:region:accountId:apis/GraphQLApiId/types/typeName/fields/fieldName`. 

Para añadir una función de Lambda como modo de autorización predeterminado en AWS AppSync:

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

1. Inicia sesión en la AWS AppSync consola y navega hasta la API que deseas actualizar.

1. Vaya a la página de Configuración de su API.

   Cambie la autorización a nivel de API a **AWS Lambda**.

1. Elija el ARN Región de AWS y el ARN de Lambda para autorizar las llamadas a la API.
**nota**  
Se añadirá automáticamente la política principal correspondiente, lo que permitirá a AWS AppSync llamar a la función de Lambda. 

1. Si lo desea, configure el TTL de respuesta y la expresión regular de validación del token.

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

1. Adjunte la política siguiente a la función de Lambda que se esté utilizando:

   ```
   aws lambda add-permission --function-name "my-function" --statement-id "appsync" --principal appsync.amazonaws.com --action lambda:InvokeFunction --output text 
   ```
**importante**  
Si quiere que la política de la función se bloquee en una única API de GraphQL, puede ejecutar 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. Actualice su AWS AppSync API para usar la función de Lambda ARN dada como autorizador:

   ```
   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**  
También puede incluir otras opciones de configuración, como la expresión regular del token. 

------

En el siguiente ejemplo se describe una función de Lambda que demuestra los distintos estados de autenticación y error que puede tener una función de Lambda cuando se utiliza como mecanismo de autorización de 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 {}
```

### Elusión de las limitaciones de autorización de los tokens SiGv4 y OIDC
<a name="aws-lambda-authorization-create-new-auth-token"></a>

Pueden usarse los métodos siguientes para eludir el problema de no poder usar su firma SigV4 o su token OIDC como token de autorización de Lambda cuando están habilitados ciertos modos de autorización.

Si desea utilizar la firma SigV4 como token de autorización de Lambda cuando estén habilitados los modos de autorización `AWS_IAM` y `AWS_LAMBDA` para la API de AWS AppSync, haga lo siguiente:
+ Para crear un nuevo token de autorización de Lambda, añada sufijos y prefijos aleatorios a la firma and/or SigV4.
+ Para recuperar la firma SiGv4 original, actualice la función Lambda eliminando los and/or sufijos de prefijos aleatorios del token de autorización de Lambda. A continuación, utilice la firma SigV4 original para la autenticación.

Si desea utilizar el token OIDC como token de autorización de Lambda cuando el modo de autorización o los modos de `OPENID_CONNECT` `AWS_LAMBDA` autorización `AMAZON_COGNITO_USER_POOLS` y estén habilitados para la API, haga AWS AppSync lo siguiente:
+ Para crear un nuevo token de autorización de Lambda, añada sufijos y prefijos aleatorios al token and/or OIDC. El token de autorización de Lambda no debe contener un prefijo de esquema Bearer.
+ Para recuperar el token OIDC original, actualice la función Lambda eliminando los sufijos de prefijos aleatorios del token de autorización and/or de Lambda. A continuación, utilice el token OIDC original para la autenticación.

## AWS\$1IAM autorización
<a name="aws-iam-authorization"></a>

Este tipo de autorización aplica el [proceso de firma Signature Version 4 de AWS](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) a la API de GraphQL. Con este tipo de autorización puede asociar políticas de acceso de Identity and Access Management ([IAM](https://aws.amazon.com/iam/)). Su aplicación puede beneficiarse de esta asociación mediante el uso de una clave de acceso (que se compone de un ID de clave de acceso y una clave de acceso secreta) o mediante el uso de credenciales temporales con una vida útil corta proporcionadas por las identidades federadas de Amazon Cognito.

Si desea un rol que pueda realizar todas las operaciones de datos:

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

****  

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

------

Puedes encontrarla en la página principal `YourGraphQLApiId` de listados de API de la AppSync consola, justo debajo del nombre de tu API. También puede obtenerla desde la CLI: `aws appsync list-graphql-apis` 

Si desea restringir el acceso a determinadas operaciones de GraphQL, puede hacerlo para los campos raíz `Query`, `Mutation` y `Subscription`.

------
#### [ 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 ejemplo, supongamos que tiene el siguiente esquema y desea restringir el acceso a todas las publicaciones:

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

type Query {
   posts:[Post!]!
}

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

La política de IAM correspondiente a un rol (que podría asociar, por ejemplo, a un grupo de identidades de Amazon Cognito) tendría un aspecto similar al siguiente:

------
#### [ 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 autorización
<a name="openid-connect-authorization"></a>

Este tipo de autorización aplica tokens de [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) (OIDC) proporcionados por un servicio compatible con OIDC. Su aplicación puede aprovechar los usuarios y los privilegios definidos por su proveedor OIDC para controlar el acceso.

Una URL de emisor es el único valor de configuración necesario que debe proporcionar a AWS AppSync (por ejemplo, `https://auth.example.com`). Esta URL debe poder direccionarse a través de HTTPS. AWS AppSync [se añade `/.well-known/openid-configuration` a la URL del emisor y localiza la configuración de OpenID según la especificación OpenID Connect `https://auth.example.com/.well-known/openid-configuration` Discovery.](https://openid.net/specs/openid-connect-discovery-1_0.html) Espera recuperar un documento JSON [RFC5785](https://tools.ietf.org/html/rfc5785)compatible en esta URL. Este documento JSON debe contener una `jwks_uri` clave que apunte al documento del conjunto de claves web JSON (JWKS) con las claves de firma. AWS AppSync requiere que los JWKS contengan los campos JSON de y. `kty` `kid`

AWS AppSync admite una amplia gama de algoritmos de firma.


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

Le recomendamos utilizar los algoritmos de RSA. Los tokens emitidos por el proveedor deben incluir la hora a la que se emitió el token (`iat`) y también pueden incluir la hora en que se autenticó (`auth_time`). Puede proporcionar valores de TTL para el tiempo de emisión (`iatTTL`) y para el tiempo de autenticación (`authTTL`) en la configuración de OpenID Connect para una validación adicional. Si su proveedor autoriza varias aplicaciones, también puede proporcionar una expresión regular (`clientId`) que se utiliza para autorizar por ID de cliente. Cuando `clientId` está presente en la configuración de OpenID Connect, AWS AppSync valida la afirmación exigiendo que coincida con la `clientId` afirmación `aud` o con la `azp` afirmación del token.

Para validar varios clientes, IDs utilice el operador de canalización («\$1»), que es una «o» en una expresión regular. Por ejemplo, si su aplicación OIDC tiene cuatro clientes con un cliente IDs como 0A1S2D, 1F4G9H, 1J6L4B, 6 GS5 MG, para validar solo los tres primeros clientes IDs, debe colocar 1F4G9H\$11J6L4B\$16 GS5 MG en el campo ID de cliente.

Si una API está configurada con varios tipos de autorización, AWS AppSync valida el emisor (afirmación iss) presente en el token JWT a partir de los encabezados de las solicitudes comparándolo con la URL del emisor especificada en la configuración de la API. Sin embargo, cuando una API se configura solo con OPENID\$1CONNECT autorización, AWS AppSync omite este paso de validación de la URL del emisor.

## AMAZON\$1COGNITO\$1USER\$1POOLS autorización
<a name="amazon-cognito-user-pools-authorization"></a>

Este tipo de autorización aplica tokens de OIDC proporcionados por grupos de usuarios de Amazon Cognito. Su aplicación puede aprovechar los usuarios y grupos de sus grupos de usuarios y de otros grupos de usuarios de otra AWS cuenta y asociarlos a campos de GraphQL para controlar el acceso.

Si utiliza agrupaciones de usuarios de Amazon Cognito, puede crear grupos a los que pertenecen los usuarios. Esta información está codificada en un token JWT al que la aplicación envía AWS AppSync en un encabezado de autorización al enviar operaciones de GraphQL. Puede utilizar directivas de GraphQL en el esquema para controlar qué grupos pueden invocar cuáles solucionadores para un campo. De este modo otorgará un acceso más controlado a los usuarios.

Por ejemplo, suponga que tiene el siguiente esquema de GraphQL:

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

type Query {
   posts:[Post!]!
}

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

Si tiene dos grupos en las agrupaciones de usuarios de Amazon Cognito (blogueros y lectores) y desea restringir el acceso de los lectores para que no puedan añadir nuevas entradas, entonces su esquema debería tener el siguiente aspecto:

```
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"])
}
...
```

Ten en cuenta que puedes omitir la `@aws_auth` directiva si quieres seguir una grant-or-deny estrategia de acceso específica de forma predeterminada. Puedes especificar la grant-or-deny estrategia en la configuración del grupo de usuarios al crear tu API de GraphQL mediante la consola o mediante el siguiente comando 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"}'
```

## Uso de modos de autorización adicionales
<a name="using-additional-authorization-modes"></a>

Al añadir modos de autorización adicionales, puede configurar directamente la configuración de autorización en el nivel de la API de AWS AppSync GraphQL (es decir, el `authenticationType` campo que puede configurar directamente en el `GraphqlApi` objeto) y actúa como predeterminado en el esquema. Esto supone que cualquier tipo que no tenga una directiva específica tiene que transmitir la configuración de autorización de nivel de API.

En el nivel de esquema, puede especificar modos de autorización adicionales mediante las directivas del esquema. Puede especificar modos de autorización en los campos individuales del esquema. Por ejemplo, para la autorización `API_KEY`, debería utilizar `@aws_api_key` en los campos o las definiciones de tipo de objeto del esquema. Las siguientes directivas se admiten en los campos y las definiciones de tipo de objeto del esquema:
+  `@aws_api_key`: para especificar que el campo está autorizado por `API_KEY`.
+  `@aws_iam`: para especificar que el campo está autorizado por `AWS_IAM`.
+  `@aws_oidc`: para especificar que el campo está autorizado por `OPENID_CONNECT`.
+  `@aws_cognito_user_pools`: para especificar que el campo está autorizado por `AMAZON_COGNITO_USER_POOLS`.
+  `@aws_lambda`: para especificar que el campo está autorizado por `AWS_LAMBDA`.

No puede utilizar la directiva `@aws_auth` junto con modos de autorización adicionales. `@aws_auth` funciona únicamente en el contexto de la autorización `AMAZON_COGNITO_USER_POOLS` sin modos de autorización adicionales. No obstante, puede utilizar la directiva `@aws_cognito_user_pools` en lugar de la directiva `@aws_auth` con los mismos argumentos. La principal diferencia entre las dos es que puede especificar `@aws_cognito_user_pools` en cualquier campo y definición de tipo de objeto.

Para comprender cómo funcionan los modos de autorización adicionales y cómo se pueden especificar en un esquema, observemos el siguiente 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 este esquema, supongamos que `AWS_IAM` es el tipo de autorización predeterminado en la API AWS AppSync GraphQL. Esto significa que los campos que no tienen una directiva se protegen mediante `AWS_IAM`. Por ejemplo, es el caso del campo `getPost` del tipo `Query`. Las directivas del esquema le permiten utilizar más de un modo de autorización. Por ejemplo, puedes `API_KEY` configurarlo como un modo de autorización adicional en la API de AWS AppSync GraphQL y puedes marcar un campo mediante la `@aws_api_key` directiva (por ejemplo, `getAllPosts` en este ejemplo). Las directivas funcionan a nivel de campo, por lo que tiene que permitir que `API_KEY` también acceda al tipo `Post`. Puede hacerlo marcando cada campo del tipo `Post` con una directiva o marcando el tipo `Post` con la directiva `@aws_api_key`.

Para restringir más el acceso a los campos del tipo `Post`, puede utilizar directivas contra los campos individuales del tipo `Post` como se muestra a continuación.

Por ejemplo, puede añadir un campo `restrictedContent` al tipo `Post` y restringir el acceso a él mediante la directiva `@aws_iam`. Las solicitudes autenticadas por `AWS_IAM` podrían acceder a `restrictedContent`, pero las solicitudes de `API_KEY` no.

```
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
}
...
```

## Control de acceso detallado
<a name="fine-grained-access-control"></a>

La información anterior muestra cómo restringir o conceder acceso a determinados campos de GraphQL. Si desea establecer controles de acceso a los datos en función de determinadas condiciones (por ejemplo, en función del usuario que realiza una llamada y de si es propietario de los datos), puede utilizar plantillas de mapeo en los solucionadores. También puede aplicar una lógica de negocio más compleja, como describimos más adelante en [Filtrado de información](#aws-appsync-filtering-information).

En esta sección se muestra cómo establecer controles de acceso a los datos mediante una plantilla de asignación de solucionadores de DynamoDB.

Antes de continuar, si no está familiarizado con las plantillas de mapeo de Resolver AWS AppSync, puede revisar la referencia de plantillas de [mapeo de Resolver y la referencia de plantillas](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference) de [mapeo de Resolver para DynamoDB](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb).

En el siguiente ejemplo con DynamoDB, imagine que utiliza el esquema de publicación del blog anterior y que solo los usuarios que han creado publicaciones tienen permiso para editarlas. El proceso de evaluación del usuario consistiría en obtener las credenciales de su aplicación, por ejemplo mediante las agrupaciones de usuarios de Amazon Cognito, y transferir entonces dichas credenciales como parte de una operación de GraphQL. A continuación, la plantilla de mapeo sustituirá un valor de las credenciales (como el nombre de usuario) en una instrucción condicional que entonces se comparará con un valor de la base de datos.

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


Para agregar esta funcionalidad, añada el campo de GraphQL `editPost` como se indica a continuación:

```
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!
}
...
```

La plantilla de mapeo del solucionador para `editPost` (que se muestra en un ejemplo al final de esta sección) debe realizar una comprobación lógica con el almacén de datos para permitir editar una publicación únicamente al usuario que la creó. Dado que se trata de una operación de edición, se corresponde con un `UpdateItem` de DynamoDB. Puede realizar una comprobación condicional antes de realizar esta acción utilizando el contexto transferido para validar la identidad del usuario. Esto se almacena en un objeto `Identity` que tiene los siguientes valores:

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

Para utilizar este objeto en una llamada de `UpdateItem` de DynamoDB, debe almacenar la información de identidad del usuario en la tabla para poder compararla. En primer lugar, la mutación `addPost` debe almacenar el creador. En segundo lugar, la mutación `editPost` debe realizar la comprobación condicional antes de actualizar.

El siguiente es un ejemplo del código de solucionador para `addPost` que almacena la identidad del usuario como una columna `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 el atributo `Author` se rellena a partir del objeto `Identity`, que procede de la aplicación.

Por último, el siguiente es un ejemplo del código de solucionador para `editPost`, que solo actualiza el contenido de la publicación del blog si la solicitud proviene del usuario que la creó:

```
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;
```

En este ejemplo se utiliza `PutItem`, lo que sobrescribe todos los valores, en lugar de `UpdateItem`, pero en ambos casos se aplica el mismo principio en el bloque de instrucciones `condition`.

## Filtrado de información
<a name="aws-appsync-filtering-information"></a>

Puede haber casos en los que, aunque no se pueda controlar la respuesta del origen de datos, no se desee enviar información innecesaria a los clientes tras una solicitud de escritura o lectura correctas al origen de datos. En estos casos puede filtrar la información utilizando una plantilla de mapeo de respuesta.

Por ejemplo, imagine que no dispone de un índice adecuado en una tabla DynamoDB de publicaciones de blog (por ejemplo, un índice por `Author`). Puede utilizar el siguiente solucionador:

```
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;
}
```

El controlador de solicitudes obtiene el elemento incluso si la intermediario no es el autor que creó la publicación. Para evitar que se devuelvan todos los datos, el controlador de respuestas comprueba que el intermediario coincide con el autor del elemento. Si el intermediario no coincide con esta comprobación, solo se devuelve una respuesta nula.

## Acceso al origen de datos
<a name="data-source-access"></a>

AWS AppSync se comunica con las fuentes de datos mediante las funciones y políticas de acceso de Identity and Access Management ([IAM](https://aws.amazon.com/iam/)). Si utiliza un rol existente, es necesario añadir una política de confianza AWS AppSync para poder asumir el rol. La relación de confianza tendrá este aspecto:

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

****  

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

------

Es importante reducir el ámbito de la política de acceso para que el rol solo tenga permisos para actuar sobre el conjunto mínimo de recursos necesario. Al utilizar la AppSync consola para crear una fuente de datos y crear un rol, esto se hace automáticamente. Sin embargo, cuando se utiliza una plantilla de ejemplo integrada desde la consola de IAM para crear un rol fuera de la consola de AWS AppSync, los permisos no se reducen automáticamente al recurso, por lo que deberá hacerlo manualmente antes de instalar la aplicación en el entorno de producción.

# Casos de uso del control de acceso para proteger solicitudes y respuestas
<a name="security-authorization-use-cases"></a>

En la sección [Seguridad](security-authz.md#aws-appsync-security) ha aprendido cuáles son los diferentes modos de autorización para proteger la API. Además dicha sección contiene una introducción a los mecanismos de autorización precisos para comprender los conceptos y el flujo. Dado que AWS AppSync le permite realizar operaciones lógicas completas en los datos mediante el uso de [plantillas de mapeo](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview) de GraphQL Resolver, puede proteger los datos de lectura o escritura de una manera muy flexible mediante una combinación de identidad de usuario, condicionales e inyección de datos.

[Si no estás familiarizado con la edición de AWS AppSync Resolvers, consulta la guía de programación.](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)

## Descripción general de
<a name="overview"></a>

La concesión de acceso a los datos de un sistema se realiza normalmente a través de una [matriz de control de acceso](https://en.wikipedia.org/wiki/Access_Control_Matrix), donde la intersección de una fila (recurso) y una columna (usuario/rol) es el permiso concedido.

AWS AppSync usa los recursos de tu propia cuenta y enlaza la información de identidad (usuario/rol) en la solicitud y respuesta de GraphQL como un [objeto de contexto](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference), que puedes usar en la resolución. Esto significa que los permisos se pueden conceder de forma adecuada en operaciones de lectura o escritura en función de la lógica del solucionador. Si esta lógica se basa en el nivel de los recursos (por ejemplo, solo algunos usuarios o grupos determinados pueden acceder read/write a una fila específica de la base de datos), entonces esos «metadatos de autorización» deben almacenarse. AWS AppSync no almacena ningún dato, por lo que debe almacenar estos metadatos de autorización con los recursos para poder calcular los permisos. Normalmente los metadatos de la autorización son un atributo (columna) de una tabla de DynamoDB, por ejemplo un **propietario** o una lista de usuarios o grupos. Por ejemplo, podrían existir los atributos **lectores** y **escritores**.

En general esto significa que al leer un elemento individual de un origen de datos, ejecutará una instrucción condicional `#if () ... #end` para la plantilla de respuesta una vez que el solucionador haya leído el origen de datos. Normalmente la comprobación usará valores de usuario o grupo de `$context.identity` para realizar comprobaciones de pertenencia con los metadatos de autorización que devuelve una operación de lectura. Cuando haya varios registros, como en el caso de listas obtenidas con operaciones `Scan` o `Query` aplicadas a una tabla, la comprobación de condición se envía como parte de la operación al origen de datos usando valores de usuario o grupo similares.

Del mismo modo, al escribir datos se aplica una instrucción condicional a la acción (como `PutItem` o `UpdateItem`) a fin de comprobar si el usuario o el grupo que realiza la mutación tiene permiso para ello. A menudo, la instrucción condicional usará un valor de `$context.identity` para compararlo con los metadatos de autorización del recurso. Tanto para las plantillas de solicitud como para las de respuesta, también se pueden usar encabezados personalizados de clientes para realizar comprobaciones de validación.

## Lectura de datos
<a name="reading-data"></a>

Como se ha indicado anteriormente, los metadatos de autorización para realizar una comprobación se deben almacenar con el recurso o se deben transferir a la solicitud de GraphQL (identidad, encabezado, etc.). Como demostración, supongamos que tiene la tabla de DynamoDB siguiente:

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


La clave principal es `id` y los datos a los que se debe obtener acceso son `Data`. El resto de columnas son ejemplos de comprobaciones que puede realizar para la autorización. `Owner` es de tipo `String`, mientras que `PeopleCanAccess` y `GroupsCanAccess` son `String Sets`, como se describe en [Resolver mapping template reference for DynamoD](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb).

El diagrama de [Información general sobre plantillas de mapeo de solucionador](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview) muestra cómo la plantilla de respuesta no solo contiene el objeto de contexto, sino también los resultados del origen de datos. En las consultas de GraphQL referidas a elementos individuales puede utilizar la plantilla de respuesta para comprobar si el usuario tiene permiso para ver estos resultados o devolver un mensaje de error de autorización. Esto es lo que a veces se denomina “filtro de autorización”. En el caso de las consultas de GraphQL que devuelven listas como resultado de Scan o Query, es más eficaz hacer la comprobación en la plantilla de solicitud y devolver los datos solo si se cumple una condición de autorización. La implementación es entonces la siguiente:

1. GetItem - comprobación de autorizaciones para registros individuales. Se realiza con instrucciones `#if() ... #end`.

1. Operaciones Scan o Query: la comprobación de autorización es una instrucción `"filter":{"expression":...}`. Algunas comprobaciones habituales son de igualdad (`attribute = :input`) o si un valor se encuentra en una lista (`contains(attribute, :input)`).

En el n.º 2, `attribute` representa en ambas instrucciones el nombre de columna del registro en una tabla, por ejemplo, `Owner` en el ejemplo anterior. Puede aplicar un alias con un signo `#` y utilizar, `"expressionNames":{...}`, pero no es obligatorio. `:input` es una referencia al valor que va a comparar con el atributo de base de datos, que definirá en `"expressionValues":{...}`. Verá estos ejemplos a continuación.

### Caso de uso: el propietario puede leer
<a name="use-case-owner-can-read"></a>

Conforme a la tabla anterior, si quiere que solo se devuelvan datos cuando `Owner == Nadia` en una operación de lectura individual (`GetItem`), la plantilla será similar a la siguiente:

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

Aquí deben tenerse en cuenta algunos puntos, ya que se volverán a usar en las secciones restantes. En primer lugar, la comprobación utiliza `$context.identity.username`, que será el nombre de inicio de sesión fácil de recordar si se usan grupos de usuario de Amazon Cognito y será la identidad de usuario si se utiliza IAM (incluidas las identidades federadas de Amazon Cognito). También deben almacenarse otros valores para el propietario, como el valor único “identidad de Amazon Cognito”, que es útil cuando se federan inicios de sesión desde varias ubicaciones, y no se olvide revisar las opciones disponibles en [Resolver Mapping Template Context Reference](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference).

En segundo lugar, la comprobación condicional "else" que responde con `$util.unauthorized()` es totalmente opcional, pero se aconseja como práctica recomendada al diseñar una API de GraphQL.

### Caso de uso: acceso específico codificado
<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: filtro de una lista de resultados
<a name="use-case-filtering-a-list-of-results"></a>

En el ejemplo anterior pudimos realizar directamente una comprobación con `$context.result`, ya que se devolvía un único elemento. Sin embargo, algunas operaciones, como Scan, devuelven varios elementos en `$context.result.items`, por lo que hay que filtrar la autorización y devolver únicamente los resultados que el usuario tiene permiso para ver. Supongamos que esta vez el campo `Owner` tiene el IdentityID de Amazon Cognito establecido en el registro. En este caso, puede utilizar la siguiente plantilla de mapeo de respuestas para filtrar los registros y mostrar solo los que son propiedad del usuario:

```
#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: varias personas pueden leer
<a name="use-case-multiple-people-can-read"></a>

Otra opción de autorización frecuente consiste en permitir a un grupo de personas leer datos. En el ejemplo siguiente, `"filter":{"expression":...}` solo devuelve valores obtenidos de una tabla si el usuario que ejecuta la consulta GraphQL aparece en el conjunto `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: un grupo puede leer
<a name="use-case-group-can-read"></a>

Al igual que en el caso de uso anterior, puede ocurrir que solo las personas de uno o varios grupos tengan derecho a leer determinados elementos de una base de datos. El uso de la operación `"expression": "contains()"` es similar. Sin embargo se trata de una disyuntiva OR lógica de todos los grupos a los que puede pertenecer el usuario, lo que debe tenerse en cuenta en la pertenencia a conjuntos. En este caso hemos creado una instrucción `$expression` para cada grupo al que pertenece el usuario y la pasamos al 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)
    }
}
```

## Escritura de datos
<a name="writing-data"></a>

La escritura de datos en las mutaciones siempre se controla en la plantilla de mapeo de solicitud. En el caso de los orígenes de datos de DynamoDB, la clave radica en utilizar una expresión de condición `"condition":{"expression"...}"` adecuada que efectúe validaciones aplicando los metadatos de autorización de la tabla. En [Seguridad](security-authz.md#aws-appsync-security) proporcionamos un ejemplo que puede utilizar para comprobar el campo `Author` de una tabla. Los casos de uso de esta sección exploran otras posibilidades.

### Caso de uso: varios propietarios
<a name="use-case-multiple-owners"></a>

Partiendo del diagrama de tabla del ejemplo anterior, observemos la 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: el grupo puede crear un registro nuevo
<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: el grupo puede actualizar un 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 y privados
<a name="public-and-private-records"></a>

Los filtros condicionales también le permiten marcar datos como privados, públicos o efectuar alguna comprobación booleana. Esto puede combinarse como parte de un filtro de autorización dentro de la plantilla de respuesta. El uso de esta comprobación es una buena manera de ocultar temporalmente datos o eliminarlos de la vista sin tener que controlar la pertenencia al grupo.

Por ejemplo, supongamos que añade un atributo a cada elemento de una tabla de DynamoDB denominada `public` con el valor `yes` o `no`. La plantilla de respuesta siguiente se podría utilizar en una llamada `GetItem` para mostrar datos solo si el usuario está en un grupo que tenga acceso Y si los datos están marcados como públicos:

```
#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
```

El código anterior también puede utilizar un operador lógico O (`||`) para permitir a los usuarios leer si tienen permiso sobre un registro o si este es público:

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

En general los operadores estándar `==`, `!=`, `&&` y `||` le resultarán útiles cuando realice comprobaciones de autorización.

## Datos en tiempo real
<a name="security-real-time-data"></a>

Puede aplicar controles de acceso precisos en las suscripciones a GraphQL en el momento en que un cliente realice una suscripción utilizando las técnicas descritas anteriormente en esta documentación. Asocie un solucionador al campo de suscripción y ya podrá consultar un origen de datos y aplicar lógica condicional en la plantilla de mapeo de solicitud o en la de respuesta. También puede devolver datos adicionales al cliente, como los resultados iniciales de una suscripción, siempre que la estructura de datos coincida con la del tipo devuelto en la suscripción de GraphQL.

### Caso de uso: el usuario solo puede suscribirse a conversaciones específicas
<a name="use-case-user-can-subscribe-to-specific-conversations-only"></a>

Un caso de uso común de datos en tiempo real con suscripciones de GraphQL consiste en crear una aplicación de mensajería o de chat privado. Al crear una aplicación de chat para varios usuarios, pueden producirse conversaciones entre dos personas o entre varias personas. Los usuarios pueden agruparse en “salas” que pueden ser privadas o públicas. En consecuencia, es necesario autorizar a cada usuario a suscribirse únicamente a las conversaciones (con otro usuario o dentro de un grupo) para las que se le haya concedido permiso. Con fines de demostración, el ejemplo siguiente muestra un caso de uso sencillo de un usuario que envía un mensaje privado a otro. La configuración tiene dos tablas de Amazon DynamoDB:
+ Tabla Messages (Mensajes): (clave principal) `toUser`, (clave de ordenación) `id` 
+ Tabla Permissions (Permisos): (clave principal) `username` 

La tabla Messages almacena los mensajes que se envían a través de una mutación de GraphQL. La suscripción de GraphQL comprueba la tabla Permissions para consultar si existe una autorización en el tiempo de conexión del cliente. En el siguiente ejemplo se presupone que se usa el siguiente esquema de 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
}
```

Algunas de las operaciones estándar, como `createUserPermissions()`, no se tratan a continuación para ilustrar los solucionadores de suscripción, pero son implementaciones estándar de solucionadores de DynamoDB. En su lugar, vamos a centrarnos en los flujos de autorización de suscripción con solucionadores. Para enviar un mensaje de un usuario a otro, asocie un solucionador al campo `sendMessage()` y seleccione como origen de datos la tabla **Messages** con la plantilla de solicitud siguiente:

```
{
    "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),
    }
}
```

En este ejemplo, usaremos `$context.identity.username`. Esto devuelve la información de usuario de AWS Identity and Access Management nuestros usuarios de Amazon Cognito. La plantilla de respuesta simplemente traslada `$util.toJson($ctx.result)`. Guarde el resultado y vuelva a la página de esquema. Asocie entonces un solucionador para la suscripción `newMessage()` utilizando la tabla **Permissions** como origen de datos y la siguiente plantilla de mapeo de solicitud:

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

Use entonces la siguiente plantilla de mapeo de respuesta para realizar las comprobaciones de autorización con los datos de la tabla **Permissions**:

```
#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
```

En este caso se hacen tres comprobaciones de autorización. La primera asegura que se devuelva un resultado. La segunda garantiza que el usuario no se suscriba a mensajes destinados a otra persona. La tercera garantiza que el usuario tiene permiso para suscribirse a cualquier campo comprobando el atributo de `isAuthorizedForSubscriptions` de DynamoDB almacenado como `BOOL`.

Para probarlo, puede iniciar sesión en la AWS AppSync consola con los grupos de usuarios de Amazon Cognito y un usuario llamado «Nadia» y, a continuación, ejecutar la siguiente suscripción de GraphQL:

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

Si en la tabla **Permissions** hay un registro para el atributo de clave `username` `Nadia` con `isAuthorizedForSubscriptions` establecido en `true`, verá una respuesta correcta. Si prueba otro `username` en la consulta de `newMessage()` anterior, se devolverá un error.

# AWS WAF Utilizándolo para proteger su AWS AppSync APIs
<a name="WAF-Integration"></a>

AWS WAF es un firewall de aplicaciones web que ayuda a proteger las aplicaciones web y contra APIs los ataques. Le permite configurar un conjunto de reglas denominadas lista de control de acceso web (ACL web) que permiten, bloquean o monitorizan (cuentan) solicitudes web en función de las reglas y condiciones de seguridad web personalizables que defina. Cuando integras tu AWS AppSync API AWS WAF, obtienes más control y visibilidad del tráfico HTTP aceptado por tu API. Para obtener más información AWS WAF, consulta [Cómo AWS WAF funciona](https://docs.aws.amazon.com/waf/latest/developerguide/how-aws-waf-works.html) en la Guía para AWS WAF desarrolladores. 

Puede utilizarla AWS WAF para proteger su AppSync API de las vulnerabilidades web más comunes, como los ataques de inyección de SQL y de secuencias de comandos entre sitios (XSS). Esto podría afectar a la disponibilidad y el rendimiento de la API, comprometer la seguridad o consumir recursos excesivos. Por ejemplo, puede crear reglas para permitir o bloquear solicitudes de rangos de direcciones IP especificados, solicitudes de bloques CIDR, solicitudes que se originan en un país o región específico, solicitudes que contengan código SQL malintencionado o solicitudes que contengan secuencias de comandos malintencionadas.

También puede crear reglas que busquen una cadena o un patrón de expresión regular en encabezados HTTP, métodos, cadenas de consulta, URI y el cuerpo de la solicitud (limitado a los primeros 8 KB). Además, puede crear reglas para bloquear ataques de agentes de usuario específicos, bots malintencionados y scrapers de contenido. Por ejemplo, puede utilizar reglas basadas en la frecuencia para especificar el número de solicitudes web permitidas por IP de cliente en un periodo de 5 minutos actualizado constantemente.

[Para obtener más información sobre los tipos de reglas compatibles y las AWS WAF funciones adicionales, consulta la [Guía para AWS WAF desarrolladores](https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html) y la Referencia de la API.AWS WAF](https://docs.aws.amazon.com/waf/latest/APIReference/API_Types_AWS_WAFV2.html)

**importante**  
AWS WAF es su primera línea de defensa contra los exploits web. Cuando AWS WAF está habilitada en una API, AWS WAF las reglas se evalúan antes que otras funciones de control de acceso, como la autorización de claves de API, las políticas de IAM, los tokens OIDC y los grupos de usuarios de Amazon Cognito. 

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

Puede integrar una API de Appsync AWS WAF utilizando el Consola de administración de AWS AWS CLI AWS CloudFormation, el o cualquier otro cliente compatible.

**Para integrar una AWS AppSync API con AWS WAF**

1. Cree una ACL AWS WAF web. Para ver los pasos detallados para utilizar la [consola de AWS WAF](https://console.aws.amazon.com/waf/), consulte [Crear una ACL web](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-creating.html).

1. Defina las reglas de la ACL web. Se definen una o varias reglas en el proceso de creación de la ACL web. Para obtener información sobre cómo estructurar las reglas, consulte [Reglas de AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rules.html). Para ver ejemplos de reglas útiles que puede definir para su AWS AppSync API, consulte[Creación de reglas para una ACL web](#Creating-web-acl-rules).

1. Asocie la ACL web a una AWS AppSync API. Puede realizar este paso en la [AWS WAF consola](https://console.aws.amazon.com/wafv2/) o en la [AppSync consola](https://console.aws.amazon.com/appsync/). 
   + Para asociar la ACL web a una AWS AppSync API de la AWS WAF consola, siga las instrucciones para [asociar o desasociar una ACL web a un AWS recurso](https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-associating-aws-resource.html) de la AWS WAF Guía para desarrolladores.
   + Para asociar la ACL web a una AWS AppSync API en la consola AWS AppSync 

     1. Inicie sesión en la [AppSync consola Consola de administración de AWS y ábrala](https://console.aws.amazon.com/appsync/).

     1. Elija la API que desee asociar a una ACL web.

     1. En el panel de navegación, seleccione **Configuración**.

     1. En la sección **Firewall de aplicaciones web**, active **Habilitar AWS WAF**.

     1. En la lista desplegable **ACL web**, elija el nombre de la ACL web que desee asociar a su API.

     1. Seleccione **Guardar** para asociar la ACL web con la API.

   

**nota**  
Después de crear una ACL web en la AWS WAF consola, la nueva ACL web puede tardar unos minutos en estar disponible. Si no ve una ACL web recién creada en el menú **Firewall de aplicaciones web**, espere unos minutos y vuelva a intentar los pasos para asociar la ACL web a su API.

**nota**  
AWS WAF la integración solo admite el `Subscription registration message` evento para puntos finales en tiempo real. AWS AppSync responderá con un mensaje de error en lugar de un `start_ack` mensaje para los `Subscription registration message` bloqueados por AWS WAF. 

Después de asociar una ACL web a una AWS AppSync API, administrará la ACL web mediante la AWS WAF APIs. No necesita volver a asociar la ACL web a su AWS AppSync API a menos que desee asociar la AWS AppSync API a una ACL web diferente.

## Creación de reglas para una ACL web
<a name="Creating-web-acl-rules"></a>

Las reglas definen cómo inspeccionar las solicitudes web y qué hacer cuando una solicitud web coincida con los criterios de inspección. Las reglas no existen AWS WAF por sí solas. Puede acceder a una regla por su nombre en el grupo de reglas o en la ACL web donde está definida. Para obtener más información, consulte [Reglas de AWS WAF](https://docs.aws.amazon.com/waf/latest/developerguide/waf-rules.html). Los siguientes ejemplos muestran cómo definir y asociar reglas que son útiles para proteger una AppSync API.

**Example Regla de ACL web para limitar el tamaño del cuerpo de la solicitud**  
El siguiente es un ejemplo de una regla que limita el tamaño del cuerpo de las solicitudes. Esto se introduciría en el **editor JSON de reglas** al crear una ACL web en la AWS WAF consola.  

```
{
    "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
        }
}
```
Una vez que haya creado su ACL web con la regla del ejemplo anterior, debe asociarla a su AppSync API. Como alternativa al uso de Consola de administración de AWS, puede realizar este paso AWS CLI ejecutando el siguiente comando.  

```
aws waf associate-web-acl --web-acl-id waf-web-acl-arn --resource-arn appsync-api-arn
```
Los cambios pueden tardar unos minutos en propagarse, pero después de ejecutar este comando, las solicitudes que contengan un cuerpo superior a 1024 bytes serán rechazadas por AWS AppSync.  
Después de crear una nueva ACL web en la AWS WAF consola, la ACL web puede tardar unos minutos en estar disponible para asociarse a una API. Si ejecuta el comando de la CLI y aparece un error `WAFUnavailableEntityException`, espere unos minutos y vuelva a intentar ejecutar el comando.

**Example Regla de ACL web para limitar las solicitudes desde una única dirección IP**  
El siguiente es un ejemplo de una regla que limita una AppSync API a 100 solicitudes desde una sola dirección IP. Esto se introduciría en el **editor JSON de reglas** al crear una ACL web con una regla basada en la velocidad en la consola. AWS WAF   

```
{
  "Name": "Throttle",
  "Priority": 0,
  "Action": {
    "Block": {}
  },
  "VisibilityConfig": {
    "SampledRequestsEnabled": true,
    "CloudWatchMetricsEnabled": true,
    "MetricName": "Throttle"
  },
  "Statement": {
    "RateBasedStatement": {
      "Limit": 100,
      "AggregateKeyType": "IP"
    }
  }
}
```
Una vez que haya creado su ACL web con la regla del ejemplo anterior, debe asociarla a su AppSync API. Para realizar este paso, ejecute el siguiente comando. AWS CLI   

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

**Example Regla de ACL web para evitar consultas de introspección \$1\$1schema de GraphQL a una API**  
El siguiente es un ejemplo de una regla que impide las consultas de introspección \$1\$1schema de GraphQL a una API. Se bloqueará cualquier cuerpo HTTP que incluya la cadena “\$1\$1schema”. Esto se introduciría en el **editor Rule JSON** al crear una ACL web en la AWS WAF consola.  

```
{
  "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
        }
      ]
    }
  }
}
```
Una vez que haya creado su ACL web con la regla del ejemplo anterior, debe asociarla a su AppSync API. Para realizar este paso, ejecute el siguiente comando. AWS CLI   

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