Derechos y feature flags, definidos por la licencia
Cómo habilitar funciones y aplicar límites numéricos según el nivel de licencia: plantillas de derechos firmadas, lectura de flags y límites sin conexión en tu app, aplicación en la frontera de cada capacidad, y cambiar lo que desbloquea un nivel sin publicar una nueva versión.
La mayoría de los tutoriales de licenciamiento se detienen en un booleano: ¿la licencia es válida o no? Eso responde si el cliente puede ejecutar tu software en absoluto. No responde la pregunta que tu producto en realidad hace cien veces al día: ¿qué está permitido hacer a este cliente en concreto? ¿Puede usar SSO? ¿Exportar a PDF? ¿Crear su undécimo proyecto? De eso se ocupan los derechos (entitlements): capacidades con nombre asociadas a una licencia, leídas localmente por tu app.
La forma de un derecho
Un derecho es una de dos cosas:
- Un feature flag — una capacidad booleana, nombrada por lo que desbloquea:
sso,export,api-access,white-label. - Un límite numérico — un tope que la app aplica:
max-projects,max-seats,api-calls-per-day.
Estos viven en un nivel (por ejemplo Free, Pro, Enterprise) como plantilla. Al emitir una licencia en un nivel, hereda los derechos de ese nivel, y quedan incrustados en la licencia firmada que el cliente activa. Una licencia Pro podría llevar { sso: false, export: true, "max-projects": 25 }; Enterprise, { sso: true, export: true, "max-projects": -1 } (usando -1 para ilimitado).
Leer los derechos en tu app
Tras la activación, el SDK almacena en caché una lease firmada y analiza sus derechos. Los lees de forma síncrona, sin llamada de red:
var client = KeyrightClient.Initialize(options);
var info = await client.ActivateAsync(licenseKey); // once; the lease is then cached
// Later, anywhere in your app:
if (client.IsEnabled("sso"))
EnableSingleSignOn();
int maxProjects = client.GetLimit("max-projects", fallback: 1);
Dos propiedades hacen esto seguro. Primero, falla hacia el estado bloqueado: un flag desconocido devuelve false, y un límite ausente devuelve el fallback que indiques, así que pasas el valor más conservador, nunca uno optimista. Segundo, es sin conexión: la plantilla de derechos forma parte de la lease firmada, verificada contra la clave pública que embebes en tiempo de compilación. Altera cualquier valor y la firma deja de coincidir, de modo que la comprobación falla en vez de conceder de más en silencio.
Aplica en la frontera de la capacidad, no solo en la interfaz
Ocultar un botón «Exportar» atenuado es buena UX, pero no es aplicación de la regla: cualquiera puede llamar al método que hay detrás. Pon la comprobación real en la frontera de la propia capacidad: la función que hace la acción.
public Report ExportToPdf(ExportOptions options)
{
if (!_license.IsEnabled("export"))
throw new FeatureNotLicensedException("export");
return _renderer.Render(options);
}
Los límites numéricos se aplican en el momento de la creación, donde ya conoces el recuento actual:
public Project CreateProject(string name)
{
int limit = _license.GetLimit("max-projects", fallback: 1);
if (limit >= 0 && _store.ProjectCount() >= limit)
throw new LimitReachedException("max-projects", limit);
return _store.Add(name);
}
Fíjate en la guarda limit >= 0: un límite negativo (-1) significa ilimitado, así que el tope se omite. Elegir un único centinela para «ilimitado» y aplicarlo de forma coherente mantiene honesto cada punto de llamada.
Cambia lo que desbloquea un nivel sin publicar una versión
Como los derechos se definen en el nivel, del lado del servidor, reempaquetar es un cambio de configuración, no de código. Añade api-access al nivel Pro y cada licencia Pro lo recoge en su siguiente actualización: sin nueva versión, sin reemitir claves, sin acción del cliente. Lanza un nuevo complemento activando un solo flag en los niveles que deban tenerlo. Esta es la verdadera recompensa del modelo capacidad-no-plan: tu empaquetado y tu cadencia de publicación se vuelven independientes.
También abarata los experimentos de precios. Mueve export de Enterprise a Pro durante un trimestre, mide la conversión, vuelve a moverlo: todo sin tocar la aplicación que ejecutan tus clientes.
Reglas de diseño que envejecen bien
- Nombra los flags por capacidad, no por plan.
export, nopro-feature. Cuando más tarde dividas Pro en Pro y Team, nada en tu código tendrá que cambiar. - Haz los límites numéricos y falla al mínimo. El fallback que pasas a
GetLimitdebería ser el valor del nivel más bajo, para que un derecho ausente o malformado degrade con elegancia en vez de desbloquearlo todo. - Nunca reutilices el nombre de un flag retirado. Si eliminas
legacy-sync, no recicles la clave para otra cosa: leases antiguas en caché aún pueden llevarla. Trata las claves de derechos como un vocabulario de solo adición. - Decide qué hace la caducidad por capacidad. Cuando una licencia entra en su ventana de gracia, algunos productos mantienen activas las funciones de solo lectura y solo bloquean la escritura; otros se detienen por completo. Codifica esa política donde lees el flag, no dispersa por la interfaz.
Los derechos convierten una licencia de una puerta en un contrato que tu código puede consultar. Una vez que las funciones y los límites fluyen desde una plantilla firmada, «mejora a este cliente» y «publica esta función para todos los de Pro» dejan de ser tareas de ingeniería y se convierten en un interruptor, que es justo donde debe estar ese control.
Prueba Nebula.NET
Endurece tu código .NET en minutos — empieza con la edición gratuita.