Autenticación de usuarios con una base de datos de documentos de Azure Cosmos DB y Xamarin.Forms

Las bases de datos de documentos de Azure Cosmos DB admiten colecciones con particiones, que pueden abarcar varios servidores y particiones, a la vez que admiten un almacenamiento y un rendimiento ilimitados. En este artículo se explica cómo combinar el control de acceso con colecciones con particiones, de modo que un usuario solo pueda acceder a sus propios documentos en una aplicación de Xamarin.Forms.

Información general

Se debe especificar una clave de partición al crear una colección con particiones y los documentos con la misma clave de partición se almacenarán en la misma partición. Por lo tanto, especificar la identidad del usuario como clave de partición dará como resultado una colección con particiones que solo almacenará documentos para ese usuario. Esto también garantiza que la base de datos de documentos de Azure Cosmos DB se escale a medida que aumente el número de usuarios y elementos.

Se debe conceder acceso a cualquier colección y el modelo de control de acceso de Azure Cosmos DB for NoSQL define dos tipos de construcciones de acceso:

  • Las claves maestras habilitan el acceso administrativo completo a todos los recursos de una cuenta de Azure Cosmos DB y se crean cuando se crea una cuenta de Azure Cosmos DB.
  • Los tokens de recursos capturan la relación entre el usuario de una base de datos y el permiso que tiene el usuario para un recurso específico de Azure Cosmos DB, como una colección o un documento.

La exposición de una clave maestra abre una cuenta de Azure Cosmos DB a la posibilidad de uso malintencionado o negligencia. Sin embargo, los tokens de recursos de Azure Cosmos DB proporcionan un mecanismo seguro para permitir que los clientes lean, escriban y eliminen recursos específicos en una cuenta de Azure Cosmos DB según los permisos concedidos.

Un enfoque típico para solicitar, generar y entregar tokens de recursos a una aplicación móvil es usar un agente de tokens de recursos. En el diagrama siguiente se muestra información general de alto nivel sobre cómo la aplicación de ejemplo usa un agente de token de recursos para administrar el acceso a los datos de la base de datos del documento:

Proceso de autenticación de base de datos de documentos

El agente de token de recursos es un servicio de API web de nivel medio, hospedado en Azure App Service, que posee la clave maestra de la cuenta de Azure Cosmos DB. La aplicación de ejemplo usa el agente de token de recursos para administrar el acceso a los datos de la base de datos de documentos de la siguiente manera:

  1. Al iniciar sesión, la aplicación Xamarin.Forms se pone en contacto con Azure App Service para iniciar un flujo de autenticación.
  2. Azure App Service realiza un flujo de autenticación de OAuth con Facebook. Una vez completado el flujo de autenticación, la aplicación Xamarin.Forms recibe un token de acceso.
  3. La aplicación Xamarin.Forms usa el token de acceso para solicitar un token de recurso desde el agente de tokens de recursos.
  4. El agente de token de recursos usa el token de acceso para solicitar la identidad del usuario desde Facebook. A continuación, la identidad del usuario se usa para solicitar un token de recurso de Azure Cosmos DB, que se usa para conceder acceso de lectura y escritura a la colección particionada del usuario autenticado.
  5. La aplicación Xamarin.Forms usa el token de recurso para acceder directamente a los recursos de Azure Cosmos DB con los permisos definidos por el token de recursos.

Nota:

Cuando expire el token de recurso, las solicitudes posteriores de la base de datos de documentos recibirán una excepción 401 no autorizada. En este momento, las aplicaciones Xamarin.Forms deben volver a establecer la identidad y solicitar un nuevo token de recurso.

Para más información sobre la creación de particiones de Azure Cosmos DB, consulte Creación de particiones y escalado en Azure Cosmos DB. Para más información sobre el control de acceso de Azure Cosmos DB, consulte Protección del acceso a datos de Azure Cosmos DB y Control de acceso en Azure Cosmos DB for NoSQL.

Configuración

El proceso para integrar el agente de token de recursos en una aplicación Xamarin.Forms es el siguiente:

  1. Cree una cuenta de Azure Cosmos DB que usará el control de acceso. Para más información, consulte Configuración de Azure Cosmos DB.
  2. Cree una instancia de Azure App Service para hospedar el agente de token de recursos. Para más información, consulte Configuración de Azure App Service.
  3. Cree una aplicación de Facebook para realizar la autenticación. Para obtener más información, consulte Configuración de una aplicación de Facebook.
  4. Configure Azure App Service para realizar una autenticación sencilla con Facebook. Para más información, consulte Configuración de autenticación de Azure App Service.
  5. Configure la aplicación de ejemplo Xamarin.Forms para comunicarse con Azure App Service y Azure Cosmos DB. Para obtener más información, consulte Configuración de la aplicación Xamarin.Forms.

Nota:

Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.

Configuración de Azure Cosmos DB

El proceso para crear una cuenta de Azure Cosmos DB que usará el control de acceso es el siguiente:

  1. Cree una cuenta de Azure Cosmos DB. Para más información, consulte Creación de una cuenta de Azure Cosmos DB.
  2. En la cuenta de Azure Cosmos DB, cree una nueva colección denominada UserItems, especificando una clave de partición de /userid.

Configuración de Azure App Service

El proceso para hospedar el agente de token de recursos en Azure App Service es el siguiente:

  1. En Azure Portal, cree una nueva aplicación web de App Service. Para más información, consulte Creación de una aplicación web en una instancia de App Service Environment.

  2. En Azure Portal, abra la hoja Configuración de la aplicación para la aplicación web y agregue la siguiente configuración:

    • accountUrl: el valor debe ser la dirección URL de la cuenta de Azure Cosmos DB de la hoja Claves de la cuenta de Azure Cosmos DB.
    • accountKey: el valor debe ser la clave maestra de Azure Cosmos DB (principal o secundaria) de la hoja Claves de la cuenta de Azure Cosmos DB.
    • databaseId: el valor debe ser el nombre de la base de datos de Azure Cosmos DB.
    • collectionId: el valor debe ser el nombre de la colección de Azure Cosmos DB (en este caso, UserItems).
    • hostUrl: el valor debe ser la dirección URL de la aplicación web en la hoja Información general de la cuenta de App Service.

    En la captura de pantalla siguiente se muestra esta configuración:

    Configuración de la aplicación web de App Service

  3. Publique la solución de agente de token de recursos en la aplicación web de Azure App Service.

Configuración de aplicaciones de Facebook

El proceso para crear una aplicación de Facebook para realizar la autenticación es el siguiente:

  1. Cree una aplicación de Facebook. Para obtener más información, vea Registrar y configurar una aplicación en el Centro para desarrolladores de Facebook.
  2. Agregue el producto de Inicio de sesión de Facebook a la aplicación. Para obtener más información, consulte Agregar inicio de sesión de Facebook a su aplicación o sitio web en el Centro para desarrolladores de Facebook.
  3. Configure el inicio de sesión de Facebook de la manera siguiente:
    • Habilite inicio de sesión OAuth de cliente.
    • Habilite el inicio de sesión OAuth web.
    • Establezca el URI de redirección de OAuth válido en el URI de la aplicación web de App Service, con /.auth/login/facebook/callback anexado.

En la captura de pantalla siguiente se muestra esta configuración:

Configuración de OAuth de inicio de sesión de Facebook

Para obtener más información, consulte Registro de la aplicación con Facebook.

Configuración de autenticación de Azure App Service

El proceso para configurar la autenticación sencilla de App Service es el siguiente:

  1. En Azure Portal, vaya a la aplicación web de App Service.

  2. En Azure Portal, abra la hoja Autenticación y autorización y realice la siguiente configuración:

    • La autenticación de App Service debe estar activada.
    • La acción que se debe realizar cuando una solicitud no está autenticada debe establecerse en Iniciar sesión con Facebook.

    En la captura de pantalla siguiente se muestra esta configuración:

    Configuración de autenticación de aplicaciones web de App Service

La aplicación web de App Service también debe configurarse para comunicarse con la aplicación de Facebook para habilitar el flujo de autenticación. Para ello, seleccione el proveedor de identidades de Facebook y escriba los valores id. de aplicación y Secreto de aplicación de la configuración de la aplicación de Facebook en el Centro para desarrolladores de Facebook. Para obtener más información, consulte Agregar información de Facebook a la aplicación.

Configuración de la aplicación Xamarin.Forms

El proceso para configurar la aplicación de ejemplo Xamarin.Forms es el siguiente:

  1. Abra la solución Xamarin.Forms.
  2. Abra Constants.cs y actualice los valores de las siguientes constantes:
    • EndpointUri: el valor debe ser la dirección URL de la cuenta de Azure Cosmos DB de la hoja Claves de la cuenta de Azure Cosmos DB.
    • DatabaseName: el valor debe ser el nombre de la base de datos del documento.
    • CollectionName: el valor debe ser el nombre de la colección de base de datos de documentos (en este caso, UserItems).
    • ResourceTokenBrokerUrl: el valor debe ser la dirección URL de la aplicación web del agente de token de recursos en la hoja Información general de la cuenta de App Service.

Inicio de sesión

La aplicación de ejemplo inicia el proceso de inicio de sesión mediante la redirección de un explorador a una dirección URL del proveedor de identidades, como se muestra en el código de ejemplo siguiente:

var auth = new Xamarin.Auth.WebRedirectAuthenticator(
  new Uri(Constants.ResourceTokenBrokerUrl + "/.auth/login/facebook"),
  new Uri(Constants.ResourceTokenBrokerUrl + "/.auth/login/done"));

Esto hace que se inicie un flujo de autenticación de OAuth entre Azure App Service y Facebook, que muestra la página de inicio de sesión de Facebook:

Inicio de sesión de Facebook

El inicio de sesión se puede cancelar presionando el botón Cancelar en iOS o presionando el botón Atrás en Android, en cuyo caso el usuario permanece sin autenticar y la interfaz de usuario del proveedor de identidades se quita de la pantalla.

Obtención de un token de recurso

Después de la autenticación correcta, se desencadena el evento WebRedirectAuthenticator.Completed. En el ejemplo de código siguiente se muestra cómo controlar este evento:

auth.Completed += async (sender, e) =>
{
  if (e.IsAuthenticated && e.Account.Properties.ContainsKey("token"))
  {
    var easyAuthResponseJson = JsonConvert.DeserializeObject<JObject>(e.Account.Properties["token"]);
    var easyAuthToken = easyAuthResponseJson.GetValue("authenticationToken").ToString();

    // Call the ResourceBroker to get the resource token
    using (var httpClient = new HttpClient())
    {
      httpClient.DefaultRequestHeaders.Add("x-zumo-auth", easyAuthToken);
      var response = await httpClient.GetAsync(Constants.ResourceTokenBrokerUrl + "/api/resourcetoken/");
      var jsonString = await response.Content.ReadAsStringAsync();
      var tokenJson = JsonConvert.DeserializeObject<JObject>(jsonString);
      resourceToken = tokenJson.GetValue("token").ToString();
      UserId = tokenJson.GetValue("userid").ToString();

      if (!string.IsNullOrWhiteSpace(resourceToken))
      {
        client = new DocumentClient(new Uri(Constants.EndpointUri), resourceToken);
        ...
      }
      ...
    }
  }
};

El resultado de una autenticación correcta es un token de acceso, que está disponible en la propiedad AuthenticatorCompletedEventArgs.Account. El token de acceso se extrae y se usa en una solicitud GET a la API resourcetoken del agente de token de recursos.

La API resourcetoken usa el token de acceso para solicitar la identidad del usuario desde Facebook, que a su vez se usa para solicitar un token de recurso desde Azure Cosmos DB. Si ya existe un documento de permisos válido para el usuario en la base de datos de documentos, se recupera y se devuelve un documento JSON que contiene el token de recurso a la aplicación Xamarin.Forms. Si no existe un documento de permisos válido para el usuario, se crea un usuario y un permiso en la base de datos de documentos y el token de recurso se extrae del documento de permisos y se devuelve a la aplicación Xamarin.Forms en un documento JSON.

Nota:

Un usuario de base de datos de documentos es un recurso asociado a una base de datos de documentos y cada base de datos puede contener cero o más usuarios. Un permiso de base de datos de documentos es un recurso asociado a un usuario de base de datos de documentos y cada usuario puede contener cero o más permisos. Un recurso de permiso proporciona acceso a un token de seguridad que el usuario requiere al intentar acceder a un recurso como un documento.

Si la API resourcetoken se completa correctamente, enviará el código de estado HTTP 200 (CORRECTO) en la respuesta, junto con un documento JSON que contiene el token de recurso. Los siguientes datos JSON muestran un mensaje de respuesta correcto típico:

{
  "id": "John Smithpermission",
  "token": "type=resource&ver=1&sig=zx6k2zzxqktzvuzuku4b7y==;a74aukk99qtwk8v5rxfrfz7ay7zzqfkbfkremrwtaapvavw2mrvia4umbi/7iiwkrrq+buqqrzkaq4pp15y6bki1u//zf7p9x/aefbvqvq3tjjqiffurfx+vexa1xarxkkv9rbua9ypfzr47xpp5vmxuvzbekkwq6txme0xxxbjhzaxbkvzaji+iru3xqjp05amvq1r1q2k+qrarurhmjzah/ha0evixazkve2xk1zu9u/jpyf1xrwbkxqpzebvqwma+hyyaazemr6qx9uz9be==;",
  "expires": 4035948,
  "userid": "John Smith"
}

El controlador de eventos WebRedirectAuthenticator.Completed lee la respuesta de la API resourcetoken y extrae el token de recurso y el identificador de usuario. A continuación, el token de recurso se pasa como argumento al constructor DocumentClient, que encapsula el punto de conexión, las credenciales y la directiva de conexión que se usa para acceder a Azure Cosmos DB y se usa para configurar y ejecutar solicitudes en Azure Cosmos DB. El token de recurso se envía con cada solicitud para acceder directamente a un recurso e indica que se concede acceso de lectura y escritura a la colección con particiones de los usuarios autenticados.

Recuperación de documentos

La recuperación de documentos que solo pertenecen al usuario autenticado se puede lograr mediante la creación de una consulta de documento que incluya el identificador del usuario como clave de partición y se muestra en el ejemplo de código siguiente:

var query = client.CreateDocumentQuery<TodoItem>(collectionLink,
                        new FeedOptions
                        {
                          MaxItemCount = -1,
                          PartitionKey = new PartitionKey(UserId)
                        })
          .Where(item => !item.Id.Contains("permission"))
          .AsDocumentQuery();
while (query.HasMoreResults)
{
  Items.AddRange(await query.ExecuteNextAsync<TodoItem>());
}

La consulta recupera de forma asincrónica todos los documentos que pertenecen al usuario autenticado, de la colección especificada y los coloca en una colección de List<TodoItem> para su visualización.

El método CreateDocumentQuery<T> especifica un argumento Uri que representa la colección que se debe consultar para los documentos y un objeto FeedOptions. El objeto FeedOptions especifica que la consulta puede devolver un número ilimitado de elementos y el identificador del usuario como clave de partición. Esto garantiza que solo se devuelvan los documentos de la colección con particiones del usuario en el resultado.

Nota:

Tenga en cuenta que los documentos de permisos, creados por el agente de token de recursos, se almacenan en la misma colección de documentos que los documentos creados por la aplicación Xamarin.Forms. Por lo tanto, la consulta de documento contiene una cláusula Where que aplica un predicado de filtrado a la consulta en la colección de documentos. Esta cláusula garantiza que los documentos de permisos no se devuelvan de la colección de documentos.

Para obtener más información sobre cómo recuperar documentos de una colección de documentos, vea Recuperación de documentos de colección de documentos.

Inserción de documentos

Antes de insertar un documento en una colección de documentos, la propiedad TodoItem.UserId debe actualizarse con el valor que se usa como clave de partición, como se muestra en el ejemplo de código siguiente:

item.UserId = UserId;
await client.CreateDocumentAsync(collectionLink, item);

Esto garantiza que el documento se insertará en la colección con particiones del usuario.

Para obtener más información sobre cómo insertar un documento en una colección de documentos, vea Inserción de un documento en una colección de documentos.

Eliminación de documentos

El valor de clave de partición debe especificarse al eliminar un documento de una colección con particiones, como se muestra en el ejemplo de código siguiente:

await client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(Constants.DatabaseName, Constants.CollectionName, id),
                 new RequestOptions
                 {
                   PartitionKey = new PartitionKey(UserId)
                 });

Esto garantiza que Azure Cosmos DB sepa de qué colección con particiones eliminar el documento.

Para obtener más información sobre cómo eliminar un documento de una colección de documentos, vea Eliminación de un documento de una colección de documentos.

Resumen

En este artículo se explica cómo combinar el control de acceso con colecciones con particiones, de modo que un usuario solo pueda acceder a sus propios documentos de base de datos de documentos en una aplicación Xamarin.Forms. Especificar la identidad del usuario como clave de partición garantiza que una colección con particiones solo pueda almacenar documentos para ese usuario.