Logo
Empezar a leer

© 2025 - alckordev

Implementa Notificaciones Push con ASP.NET + JWT y Firebase Cloud Messaging

1 abril, 2023

6 minutos de lectura

0

Implementa Notificaciones Push con ASP.NET + JWT y Firebase Cloud Messaging

Las notificaciones push son esenciales en aplicaciones modernas, ya que permiten comunicarse con los usuarios y mantenerlos informados en tiempo real. En este artículo, describiremos cómo implementar notificaciones push en una API utilizando JSON Web Tokens (JWT) y Firebase Cloud Messaging (FCM).

Asumiremos que ya has implementado la autenticación JWT en tu proyecto de ASP.NET Core 6; si no lo has hecho, te recomiendo leer el artículo "Cómo implementar JWT en ASP.NET Core 6" antes de continuar, ya que no abordaremos este tema aquí.

Instalación de paquetes

Para habilitar el envio de notificaciones push, es necesario instalar los siguientes paquete: FirebaseAdmin y Google.Apis.Auth.OAuth2. Puedes hacer esto atraves del gestor de paquetes de NuGet.

Especificar los parametros de Firebase en el archivo appsettings.json

A continuación, debemos crear una sección en el archivo appsettings.json con la información generada en Firebase Admin SDK.

Agrega la siguiente información en el archivo appsettings.json:

// appsettings.json

{
  "Firebase": {
    "Type": "service_account",
    "ProjectId": "",
    "PrivateKeyId": "",
    "PrivateKey": "",
    "ClientEmail": "",
    "ClientId": "",
    "AuthUri": "",
    "TokenUri": "",
    "AuthProviderCertUrl": "",
    "ClientCertUrl": ""
  }
}

Crear un modelo para la notificación

Para enviar la información de la notificación, debe crear una clase Notify.cs en la carpeta Entities.

// Entities/Notify.cs

namespace ApiJWT.Entities
{
    public class Notify
    {
        public string Title { get; set; } = null!;
        public string Body { get; set; } = null!;
    }
}

Implementación del controlador de notificaciones

Para crear y configurar el controlador de notificaciones, siga los pasos a continuación:

Crear el controlador de notificaciones

Cree el siguiente archivo Controllers/NotifyController.cs y agregar el atributo [Authorize] para asegurarnos que solo los usuarios autenticados o autorizados puedan acceder.

// Controllers/NotifyController.cs

using Microsoft.AspNetCore.Mvc;

namespace ApiJWT.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class NotifyController : ControllerBase
    {
    }
}

Importar los paquetes previamente instalados

// Controllers/NotifyController.cs

using FirebaseAdmin;
using FirebaseAdmin.Messaging;
using Google.Apis.Auth.OAuth2;

Inicializar las variables y configuraciones

El constructor de NotifyController inicializa la aplicación Firebase, así como las credenciales necesarias para autenticar con Firebase. Estas credenciales se obtienen a través de la configuración, que incluye la clave privada y el ID del proyecto.

// Controllers/NotifyController.cs

namespace ApiJWT.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class NotifyController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly FirebaseApp _firebaseApp;

        public NotifyController(IConfiguration configuration)
        {
            _configuration = configuration;

            if (FirebaseApp.GetInstance("MyApp") == null)
            {
                GoogleCredential credential = GoogleCredential.FromJson($@"
                    {{
                        ""type"": ""{_configuration["Firebase:Type"]}"",
                        ""project_id"": ""{_configuration["Firebase:ProjectId"]}"",
                        ""private_key_id"": ""{_configuration["Firebase:PrivateKeyId"]}"",
                        ""private_key"": ""{_configuration["Firebase:PrivateKey"]}"",
                        ""client_email"": ""{_configuration["Firebase:ClientEmail"]}"",
                        ""client_id"": ""{_configuration["Firebase:ClientId"]}"",
                        ""auth_uri"": ""{_configuration["Firebase:AuthUri"]}"",
                        ""token_uri"": ""{_configuration["Firebase:TokenUri"]}"",
                        ""auth_provider_x509_cert_url"": ""{_configuration["Firebase:AuthProviderCertUrl"]}"",
                        ""client_x509_cert_url"": ""{_configuration["Firebase:ClientCertUrl"]}""
                    }}
                ");

                FirebaseApp.Create(new AppOptions()
                {
                    Credential = credential
                }, "MyApp");
            }

            _firebaseApp = FirebaseApp.GetInstance("MyApp");
        }
    }
}

Crear el método para enviar notificaciones

Agregue el método PostNotify, que será el punto de entrada para enviar notificaciones push a los dispositivos de los usuarios. Este método debe aceptar un objeto Notify, que contiene el título y el cuerpo de la notificación.

// Controllers/NotifyController.cs

using ApiJWT.Entities;
// ...

namespace ApiJWT.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class NotifyController : ControllerBase
    {
        // ...

        [HttpPost]
        public async Task<ActionResult> PostNotify(Notify notify)
        {
        }
    }
}

Crear una lista de tokens de dispositivos

Dentro del método PostNotify, se crea una lista de tokens de dispositivos a los que se enviarán las notificaciones.

var tokens = new List<string>
{
    // Tokens
};

Crear y enviar el mensaje

Se utiliza la clase FirebaseMessaging para crear un objeto MulticastMessage, que incluye la notificación y la lista de tokens. Luego, se envía el mensaje utilizando el método SendMulticastAsync.

var messaging = FirebaseMessaging.GetMessaging(_firebaseApp);

var message = new MulticastMessage()
{
    Notification = new Notification
    {
        Title = notify.Title,
        Body = notify.Body
    },
    Tokens = tokens
};

BatchResponse response = await messaging.SendMulticastAsync(message);

Manejar errores y devolver la respuesta

Si se encuentra un error al enviar las notificaciones, el controlador registra el error en la consola por cada token, junto con el mensaje de error. Si el envío es exitoso, se retorna una respuesta con el número de mensajes enviados correctamente y el número de mensajes que no pudieron ser enviados.

if (response.FailureCount > 0)
{
    for (int i = 0; i < tokens.Count; i++)
    {
        if (response.Responses[i].IsSuccess)
        {
            continue;
        }

        // Get the error
        var error = response.Responses[i].Exception;

        // Log the error
        Console.WriteLine($"Error sending message to token {tokens[i]}: {error}");
    }
}

return Ok(new
{
    message = $"Successfully sent {response.SuccessCount} messages. Failed to send {response.FailureCount} messages."
});

En caso de que ocurra una excepción no relacionada con el envío de notificaciones, se captura con un bloque catch y se retorna un código de estado 500 con el mensaje de error.

catch (Exception ex)
{
    return StatusCode(500, new
    {
        message = ex.Message,
    });
}

Conclusión

Este artículo presentó un enfoque paso a paso para implementar notificaciones push en una API utilizando JWT y Firebase Cloud Messaging. El ejemplo de código proporcionado es un excelente punto de partida para implementar notificaciones push en su propia aplicación. Al integrar estas funcionalidades, podrá mantener a sus usuarios informados y comprometidos con su aplicación.

A continuación, se muestra el código completo del controlador de notificaciones:

// Controllers/NotifyController.cs

using ApiJWT.Entities;
using FirebaseAdmin;
using FirebaseAdmin.Messaging;
using Google.Apis.Auth.OAuth2;
using Microsoft.AspNetCore.Mvc;

namespace ApiJWT.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class NotifyController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly FirebaseApp _firebaseApp;

        public NotifyController(IConfiguration configuration)
        {
            _configuration = configuration;

            if (FirebaseApp.GetInstance("MyApp") == null)
            {
                GoogleCredential credential = GoogleCredential.FromJson($@"
                    {{
                        ""type"": ""{_configuration["Firebase:Type"]}"",
                        ""project_id"": ""{_configuration["Firebase:ProjectId"]}"",
                        ""private_key_id"": ""{_configuration["Firebase:PrivateKeyId"]}"",
                        ""private_key"": ""{_configuration["Firebase:PrivateKey"]}"",
                        ""client_email"": ""{_configuration["Firebase:ClientEmail"]}"",
                        ""client_id"": ""{_configuration["Firebase:ClientId"]}"",
                        ""auth_uri"": ""{_configuration["Firebase:AuthUri"]}"",
                        ""token_uri"": ""{_configuration["Firebase:TokenUri"]}"",
                        ""auth_provider_x509_cert_url"": ""{_configuration["Firebase:AuthProviderCertUrl"]}"",
                        ""client_x509_cert_url"": ""{_configuration["Firebase:ClientCertUrl"]}""
                    }}
                ");

                FirebaseApp.Create(new AppOptions()
                {
                    Credential = credential
                }, "MyApp");
            }

            _firebaseApp = FirebaseApp.GetInstance("MyApp");
        }

        [HttpPost]
        public async Task<ActionResult> PostNotify(Notify notify)
        {
            try
            {
                var tokens = new List<string>
                {
                    "hoovSlFjvgc2ZioYG16r_xxx",
                    "lswZv7NpBdaHbhxEiAnG_xxx"
                };

                var messaging = FirebaseMessaging.GetMessaging(_firebaseApp);

                var message = new MulticastMessage()
                {
                    Notification = new Notification
                    {
                        Title = notify.Title,
                        Body = notify.Body
                    },
                    Tokens = tokens
                };

                BatchResponse response = await messaging.SendMulticastAsync(message);

                if (response.FailureCount > 0)
                {
                    for (int i = 0; i < tokens.Count; i++)
                    {
                        if (response.Responses[i].IsSuccess)
                        {
                            continue;
                        }

                        // Get the error
                        var error = response.Responses[i].Exception;

                        // Log the error
                        Console.WriteLine($"Error sending message to token {tokens[i]}: {error}");
                    }
                }

                return Ok(new
                {
                    message = $"Successfully sent {response.SuccessCount} messages. Failed to send {response.FailureCount} messages."
                });
            }
            catch (Exception ex)
            {
                return StatusCode(500, new
                {
                    message = ex.Message,
                });
            }
        }
    }
}

Si tienes alguna pregunta, sugerencia o comentario, no dudes en dejar un comentario en la sección de abajo. Nos encantaría conocer tus opiniones y responder a tus dudas. Además, si este artículo te resultó útil e informativo, por favor compártelo con tus colegas y amigos.

¡Gracias por leer y hasta la próxima!

test...

¿Te gustó lo que leíste?

Si lo deseas, puedes apoyarme con una donación voluntaria. Tu aporte me permite dedicar más tiempo a investigar, escribir y mejorar la calidad del contenido que publico. ¡Muchísimas gracias por considerar impulsar este proyecto!

Cómprame un café

Compartir en: