Skip to content
← Todas las publicaciones
· Delta1 Labs Licenciamiento.NETGuíaCómo-hacerlo

Cómo añadir licenciamiento de software a una aplicación .NET

Un cómo-hacerlo práctico para añadir licenciamiento a una aplicación .NET: emite una clave firmada, embebe una clave pública, verifica sin conexión, limita funciones por nivel y derechos, activa en línea para los puestos y gestiona pruebas y revocación.

Para añadir licenciamiento a una aplicación .NET emites una clave de licencia firmada desde un servidor, embebes la clave pública correspondiente en tu aplicación y verificas esa clave sin conexión contra ella al arrancar; luego limitas tus funciones de pago según el nivel o los derechos que lleve la licencia. Si necesitas hacer cumplir el número de puestos o revocar claves sobre el terreno, añades encima la activación en línea. Este cómo-hacerlo recorre todo el camino con código ligero e ilustrativo usando el SDK de Keyright.NET, y es honesto sobre qué partes son cumplimiento real y cuáles son solo un freno.

El modelo mental: firma en el servidor, verifica en el cliente

El licenciamiento construido sobre firmas de clave pública tiene una asimetría que hace todo el trabajo. Una clave privada vive en tu servidor y es lo único que puede crear una licencia válida. La clave pública correspondiente viaja dentro de tu aplicación y solo puede verificar firmas: nunca puede acuñarlas. Por eso embeber la clave pública en tu binario es seguro: un atacante puede decompilar tu aplicación, leer la clave pública, incluso publicarla, y aun así no puede falsificar una licencia, porque falsificar requiere la clave privada que no tiene.

Así que el flujo es: tu servidor firma una licencia (una pequeña carga útil JSON —licenciatario, producto, nivel, puestos, caducidad, derechos— más una firma RSA sobre ella); tu aplicación verifica esa firma sin conexión contra la clave pública embebida; y todo lo que desbloqueas depende de los campos dentro de una licencia que has confirmado como auténtica.

Paso 1 — Emite una clave de licencia firmada

Las claves se acuñan en el servidor. Con Keyright emites una desde el panel o la API de administración contra un producto y un nivel:

curl -X POST $BASE/admin/licenses -H "X-Admin-Token: $TOKEN" -H "content-type: application/json" \
  -d '{"licensee":"Acme Inc.","product":"acme-app","tier":"pro","seats":3,"email":"owner@acme.com"}'
# -> { "id": "LIC-XXXXXXXX...", ... }   this is the key the customer pastes into your app

El tier aquí (pro) lleva una plantilla de derechos: los flags y límites con nombre que hereda toda licencia de ese nivel, que comprobarás en el Paso 4. La clave de firma privada que firma esta licencia nunca sale del servidor.

Paso 2 — Embebe tu clave pública

Toma la clave pública de tu tenant (la pestaña Integration del panel, o GET /admin/public-key) y pégala en las opciones del SDK. Construye exactamente un cliente al arrancar:

using Keyright.Client;

static readonly KeyrightClient License = KeyrightClient.Initialize(new KeyrightOptions
{
    Product         = "acme-app",                          // must match the slug you issue keys for
    PublicKeyBase64 = "MIIBIjANBgkq...",                   // the public key from Step 1's tenant
    ServiceUrl      = "https://keyright.delta1labs.com",   // omit if you ship offline files only
});

Product y PublicKeyBase64 son las únicas opciones obligatorias. ServiceUrl solo se necesita si vas a activar en línea (Paso 5). Esta clave pública no es un secreto: viaja en tu binario compilado y toda la seguridad viene de que la clave privada se quede en el servidor.

Paso 3 — Verifica sin conexión al arrancar

Llama a Validate(). Encuentra la mejor licencia disponible (una cadena explícita, un archivo de licencia, una variable de entorno o un lease de activación en caché), verifica la firma RSA, la coincidencia de producto, el bloqueo por equipo, la caducidad, una lista de revocación opcional incluida en el envío y el estado de prueba/reloj, todo sin conexión, sin ninguna llamada de red. Y lo crítico: nunca lanza una excepción: ante cualquier problema devuelve un LicenseInfo en la edición Free que lleva el motivo.

LicenseInfo info = License.Validate();

if (info.IsPaid)                        // true for any edition above Free
{
    // unlock paid features
}

Siendo honestos: una comprobación sin conexión se ejecuta enteramente en la máquina del usuario, así que un atacante decidido puede eliminarla con un parche. La validación sin conexión es la herramienta adecuada para instalaciones aisladas (air-gapped) y empresariales y para una comprobación rápida al arrancar, pero por sí sola es un freno. El cumplimiento real viene de combinarla con la activación en línea (Paso 5) para que los puestos y la revocación se decidan en el servidor.

Paso 4 — Limita funciones por nivel y derechos

En lugar de ramificar según el nombre de la edición, limita cada función según los derechos: flags con nombre y límites numéricos integrados en la licencia por su nivel. Así puedes cambiar qué desbloquea un plan desde el panel sin publicar código nuevo:

// Boolean flag
if (License.IsEnabled("export"))
    ShowExportCommand();

// Numeric limit — you pass the fail-closed fallback
long maxProjects = License.GetLimit("max-projects", fallback: 1);
if (currentProjectCount >= maxProjects)
    PromptToUpgrade();

Tanto IsEnabled como GetLimit validan en el acto y fallan hacia el estado bloqueado: un flag ausente se lee como desactivado, y un límite ausente o no analizable devuelve el fallback que proporcionas. Si vas a comprobar varios derechos a la vez, valida una vez y reutiliza el resultado:

LicenseInfo info = License.Validate();
bool canExport  = info.Entitlements.IsEnabled("export");
long maxSeats   = info.Entitlements.GetLimit("max-seats", 1);

Paso 5 — Activa en línea para los puestos (opcional pero recomendado)

Cuando un cliente pega su clave, llama a ActivateAsync. Envía la clave más un identificador de máquina estable a tu servicio, que consume un puesto y devuelve un lease firmado de vida corta vinculado a esa máquina. El SDK verifica el lease contra tu clave pública embebida y lo almacena en caché localmente, de modo que cada Validate() posterior tiene éxito sin conexión hasta que transcurre la ventana de gracia del lease.

LicenseInfo info = await License.ActivateAsync(customerEnteredKey, ct);

if (info.IsValid && info.IsPaid)
{
    // Activated. Lease cached; the app now works offline until it nears expiry.
    ShowLicensedUi(info.StatusBadge);      // e.g. "Pro" or "Enterprise Trial"
}
else
{
    ShowActivationError(info.Message);     // "All seats for this license are in use.", etc.
}

Como Validate(), ActivateAsync no lanza excepciones ante fallos ordinarios (clave incorrecta, límite de puestos agotado, sin conexión, revocada): devuelve un resultado que falla hacia el estado bloqueado y que inspeccionas. Unas cuantas propiedades que conviene conocer:

  • Los puestos se hacen cumplir en el servidor. Reactivar una máquina ya vinculada es idempotente y no consume un puesto extra; superar el tope devuelve un resultado de límite de puestos y ningún lease.
  • Gracia sin conexión. Si el servicio no es alcanzable, la activación recurre a cualquier lease en caché todavía válido, así que un corte breve no deja fuera al usuario.
  • Solo lanza excepciones ante errores del programador: un ServiceUrl ausente o una clave vacía.

Este es el paso que convierte “una comprobación por sistema de honor” en cumplimiento real: el número de puestos y el estado de revocación se deciden en un servidor que tú controlas, no en la máquina del atacante.

Paso 6 — Gestiona pruebas y revocación

Las pruebas fluyen por la misma ruta de activación exacta: no hay código de prueba separado en tu aplicación. Una clave de prueba devuelve un lease con IsTrial establecido, y lo muestras directamente desde LicenseInfo:

if (info.IsTrial)
    ShowBadge($"{info.StatusBadge} — {info.DaysRemaining} days left");

Una prueba cuenta hacia atrás desde la primera activación y es sustituida sin problemas cuando el cliente activa después una clave de pago, sin reinstalar. Incluso puedes dejar que los clientes inicien una prueba desde tu propio sitio de marketing con una sola llamada pública a la API; consulta pruebas gratuitas de autoservicio.

La revocación es como matas una clave filtrada o reembolsada. Revócala en el servidor (POST /admin/licenses/{id}/revoke o un clic en el panel) y el cliente baja a Free en su siguiente refresco de lease. Para aplicaciones puramente sin conexión, incluye en tu compilación una lista de revocación firmada para que incluso un cliente desconectado la respete.

Paso 7 — Prueba la ruta de fallo hacia el estado bloqueado

La prueba más importante es que las cosas se rompan hacia bloqueado, no abierto:

  1. Antes de activar, confirma que Validate() devuelve Free y que las funciones de pago siguen bloqueadas.
  2. Activa con una clave real, observa cómo la aplicación pasa a licenciada, luego desconecta la red y reinicia: debería seguir licenciada desde el lease en caché.
  3. Revoca la clave, reconecta, deja que el lease se refresque y confirma que la aplicación vuelve a Free.
  4. Retrasa el reloj en una prueba y confirma que el SDK informa de ClockTampered y se niega a validar hasta que se corrija la hora.

El resumen honesto

Añadir licenciamiento a una aplicación .NET son dos piezas móviles: verificar una clave firmada sin conexión contra una clave pública embebida y —cuando necesitas puestos o revocación— activar en línea para obtener un lease de vida corta. Las comprobaciones del lado del cliente por sí solas son un freno que un atacante puede acabar parcheando; el cumplimiento real es el servidor decidiendo los puestos y la revocación, con el SDK fallando hacia el estado bloqueado en todo lo intermedio. El SDK de Keyright.NET te da ambas mitades —Validate() sin conexión y ActivateAsync() en línea con derechos, pruebas, bloqueo por equipo y revocación— y apunta a múltiples destinos desde .NET Framework 4.8 hasta el .NET actual. Puedes cablear todo el flujo de principio a fin en el plan gratuito antes de pagar nada.

Prueba Nebula.NET

Endurece tu código .NET en minutos — empieza con la edición gratuita.