Intégration réutilisable AuthFlow (activation de licence + vérification des
mises à jour intégrée à l'app) pour les applications ASP.NET Core Blazor
Server (Kestrel + Windows Service), extraite de la vraie intégration pilote
validée sur Brackford-0brien/FneManuelInvoiceApp (dev/web-version). Trois
packages NuGet, publiés publiquement sur nuget.org :
| Package | Contenu |
|---|---|
AuthFlow.LicenseClient |
Le SDK AuthFlow (validation de licence Ed25519 hybride online/offline, heartbeat, update-check). Source : Brackford-0brien/AuthFlow, sdk/dotnet/AuthFlow.LicenseClient. |
AuthFlow.AppKit |
Librairie de classes : store/manager/hosted-service de licence, AppUpdateService, et les composants Razor UI (AuthFlowBanner, LicenseActivation, UpdateCheck). Dépend de AuthFlow.LicenseClient. |
AuthFlow.Template |
Un template pack dotnet new (PackageType=Template) qui génère une nouvelle app Blazor Server déjà câblée avec AuthFlow.AppKit + le SDK AuthFlow, l'hébergement Kestrel/Windows Service, l'installeur Inno Setup, et le pipeline CI/CD de release générique. Aussi visible dans le sélecteur Créer un nouveau projet de Visual Studio (recherchez "authflow") une fois l'indexation nuget.org terminée. |
AuthFlow.LicenseClient n'est pas compilé depuis les sources dans ce repo -
le .nupkg pré-construit est vendored sous local-nuget-feed/ (copié depuis
une build locale du repo source AuthFlow) et republié par ce repo vers
nuget.org à chaque nouvelle version. Les consommateurs n'ont jamais besoin de
la copie vendored ni du repo source AuthFlow - juste de nuget.org.
Les 3 packages sont publics sur nuget.org, la source NuGet par défaut sur
n'importe quel poste avec le SDK .NET installé. Aucun nuget.config,
aucun PAT, aucune authentification n'est nécessaire pour les consommer -
ni pour dotnet restore/dotnet build, ni pour dotnet new install.
Historique : ces packages étaient initialement publiés sur le feed GitHub Packages (privé) de ce repo, ce qui nécessitait un PAT
read:packagescôté consommateur. Ils ont depuis été republiés sur nuget.org (public) pour que le templatedotnet newsoit utilisable sans aucune étape d'authentification et découvrable depuis Visual Studio.AuthFlow.LicenseClient/AuthFlow.AppKitrestent des bibliothèques génériques sans donnée client réelle en dur (voir "Sécurité" plus bas) - c'est ce qui rend leur publication publique acceptable.
dotnet new install AuthFlow.Template
dotnet new authflow-blazor -n MyNewApp
cd MyNewApp
dotnet buildLa valeur de -n devient le nom du projet/namespace/service, le GUID AppId
de l'installeur est régénéré automatiquement à chaque instanciation. Ajustez
les chaînes ProductDisplayName/ServiceBaseName/branding directement dans
Program.cs/appsettings.json après génération si elles doivent différer
du nom du projet.
Le .csproj généré référence déjà AuthFlow.AppKit - aucune étape
manuelle dotnet add package n'est nécessaire. AuthFlow.LicenseClient
(le SDK) est aussi résolu automatiquement, en tant que dépendance transitive
de AuthFlow.AppKit (vous ne le verrez pas comme référence top-level dans
dotnet list package - cette commande ne liste que les références directes
par défaut - mais dotnet restore / dotnet build le récupèrent sans rien
faire de plus). Vérifié pour de vrai avec dotnet list package sur un
projet fraîchement généré :
Top-level Package Requested Resolved
> AuthFlow.AppKit 0.1.1 0.1.1
> Microsoft.Extensions.Hosting.WindowsServices 10.0.0 10.0.0
> Radzen.Blazor 6.0.0 6.0.0
Ça génère un projet Blazor Server avec :
-
Program.cspré-câblé avecbuilder.Services.AddAuthFlowAppKit(...),builder.Host.UseWindowsService(...), binding Kestrel depuis la config. -
appsettings.jsonavec une sectionAuthFlowprête pour leProductId/ServerUrl/PublicKeysde votre produit. -
installer/setup.iss(Inno Setup) avec un GUIDAppIdfraîchement généré et le nom de votre app/service substitué. -
.github/workflows/release.yml- le même pipeline CI/CD générique et paramétrable validé sur FneManuelInvoiceApp (build → Inno Setup → checksum → GitHub Release sur un repo public de releases séparé). Configurez justeRELEASES_REPO/RELEASES_REPO_TOKENpour le repo de releases de la nouvelle app (voirINSTALLER.md§7 de FneManuelInvoiceApp pour les étapes exactes - non dupliquées ici pour éviter la divergence ; copiez ce doc à côté du workflow quand vous générez une nouvelle app).
-
Bumpez
<Version>danssrc/AuthFlow.AppKit/AuthFlow.AppKit.csproj(ettemplate/AuthFlow.Template.csprojsi vous avez modifié le template, ettemplate/content/AuthFlowApp1/AuthFlowApp1.csprojpour pointer la bonne version d'AuthFlow.AppKitdans le projet généré). Si le SDKAuthFlow.LicenseClienta changé, bumpez aussi sa version dansBrackford-0brien/AuthFlowet copiez le nouveau.nupkgdanslocal-nuget-feed/. -
dotnet packchaque projet modifié en local pour vérifier que ça compile et se pack sans erreur avant de publier. -
Publiez sur nuget.org, dans cet ordre de dépendance (LicenseClient d'abord, sinon la restauration d'AppKit échoue le temps que LicenseClient soit indexé) :
dotnet nuget push local-nuget-feed\AuthFlow.LicenseClient.<version>.nupkg -s https://api.nuget.org/v3/index.json -k <NUGET_ORG_API_KEY> dotnet nuget push local-nuget-feed\AuthFlow.AppKit.<version>.nupkg -s https://api.nuget.org/v3/index.json -k <NUGET_ORG_API_KEY> dotnet nuget push local-nuget-feed\AuthFlow.Template.<version>.nupkg -s https://api.nuget.org/v3/index.json -k <NUGET_ORG_API_KEY>
L'API key se génère sur https://www.nuget.org/account/apikeys (scope "Push", limité aux
PackageIdAuthFlow.*). nuget.org n'autorise pas de republier un numéro de version déjà poussé - un bump de<Version>est donc obligatoire à chaque publication, même pour un simple correctif. -
git tag vX.Y.Z && git push origin vX.Y.Zpour garder une trace de la version publiée dans l'historique git. -
Comptez quelques minutes pour l'indexation nuget.org avant qu'une nouvelle version soit résolvable par
dotnet restore, et un peu plus longtemps avant queAuthFlow.Templateapparaisse/se mette à jour dans le sélecteur Créer un nouveau projet de Visual Studio (cache côté VS, pas seulement l'indexation nuget.org).
Ça a été testé pour de vrai, pas juste supposé - deux fois :
-
Historique (feed GitHub Packages) :
.github/workflows/test-clean-consume.ymla fait tourner un runner GitHub tout neuf qui installe le template et build le projet généré avec un PATread:packagesen lecture seule. -
Actuel (nuget.org public) : depuis un dossier local totalement propre
(aucun cache NuGet réutilisé,
nuget.configlimité ànuget.org+ éventuellement un feed de staging pour tester une version pas encore indexée),dotnet new install AuthFlow.Template, puisdotnet new authflow-blazor -n TestApp, puisdotnet restoreetdotnet build -c Release- 0 warning, 0 erreur, aucune source NuGet ni aucun token GitHub configuré. C'est exactement le scénario visé par la demande client "aucune dépendance GitHub pour un dev qui crée un new projet" : nuget.org seul suffit.
-
Services/AuthFlowLicenseFileStore.cs- persiste le token.licimporté sousApp_Data/authflow-license.lic. -
Services/AuthFlowLicenseManager.cs- logique partagée d'activation+vérification (utilisée au démarrage et par la page d'import). -
Services/AuthFlowLicenseHostedService.cs+AuthFlowLicenseConfig- exécute la vérification initiale + périodique de licence en tant qu'IHostedService. Le service de heartbeat propre au SDK est enregistré séparément parAddAuthFlowLicense(depuisAuthFlow.LicenseClient) et démarré automatiquement par le même host - aucun câblage supplémentaire nécessaire. -
Services/AuthFlowLicenseState.cs- snapshot du dernier résultat de vérification à l'échelle du processus + notification de changement, lu par la bannière/pages Razor. -
Services/AppUpdateService.cs- encapsule l'IUpdateCheckerdu SDK, ajoute le téléchargement + la vérification de checksum SHA-256 + le lancement de l'installeur, avec un fallback optionnel de téléchargement authentifié via l'API GitHub pour les repos de releases privés (pas nécessaire avec le pattern recommandé de repo de releases public). -
Components/AuthFlowBanner.razor- bannière d'avertissement non bloquante (licence invalide/hors-ligne), à intégrer dans votreMainLayout. -
Components/LicenseActivation.razor- page d'upload/import de fichier.lic(/license-activation). -
Components/UpdateCheck.razor- page "vérifier les mises à jour" (/update-check), avec bouton téléchargement+installation. -
AuthFlowAppKitOptions.cs-ProductDisplayName/CompanyName/ServiceBaseName, les leviers utilisés pour dé-coder en dur les chaînes spécifiques à l'app (noms de dossiers temporaires, nom de fichier installeur de secours, User-Agent, titres UI/pied de page) qui étaient auparavant codées en dur à "FneManuelInvoiceApp" dans le code pilote d'origine. -
ServiceCollectionExtensions.cs-services.AddAuthFlowAppKit(configuration, options => {...}), l'appel unique qui câble tout ce qui précède.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthFlowAppKit(builder.Configuration, options =>
{
options.ProductDisplayName = "My New App";
options.CompanyName = "Brackford-0brien";
options.ServiceBaseName = "MyNewApp"; // used for temp folder / installer filename fallback
});
builder.Host.UseWindowsService(options =>
{
options.ServiceName = builder.Configuration["WindowsService:ServiceName"] ?? "MyNewApp";
});{
"AuthFlow": {
"ProductId": "your-product-id",
"ServerUrl": "https://auth-flow-dun.vercel.app",
"LicenseKey": "", // dev/testing fallback only - production uses the .lic import flow
"GracePeriodDays": 7,
"HeartbeatIntervalMinutes": 60,
"HttpTimeoutSeconds": 20,
"PublicKeys": {
"test-key": "MCowBQYDK2VwAyEA..."
}
},
"GitHub": {
"Token": "" // only needed if your installer releases repo is PRIVATE - not recommended, see below
}
}Les deux packages ont été construits, packagés et validés pour de vrai (pas juste compilés) :
-
dotnet packsurAuthFlow.AppKit.csprojettemplate/AuthFlow.Template.csproj→ les deux ont produit des.nupkgvalides. -
dotnet new install AuthFlow.Template.0.1.0.nupkgdepuis un feed local → le template s'est enregistré avec succès (authflow-blazor). -
dotnet new authflow-blazor -n TestApp→ génère un projet avecTestApp.csproj, un GUIDAppIdd'installeur fraîchement généré substitué danssetup.iss, et toutes les référencesAuthFlowApp1renommées enTestApp. -
dotnet buildsur le projet généré → 0 warning, 0 erreur. -
dotnet runavec un vraiProductId/LicenseKey/PublicKeysdu produit AuthFlow pilote de FneManuelInvoiceApp, contre le vrai serveur de productionhttps://auth-flow-dun.vercel.app:-
POST /api/activateetPOST /api/validateont été appelés pour de vrai (visible dans les logs), confirmant que lesAuthFlowLicenseManager/AuthFlowLicenseHostedServiceextraits fonctionnent à l'identique une fois séparés de l'app d'origine. - La licence (désormais révoquée, suite aux tests précédents du pilote) est bien revenue en
Revoked- prouvant que le pipeline de validation de signature Ed25519 du SDK fonctionne toujours de bout en bout à travers le code extrait. -
GET /api/updates/checka été appelé pour de vrai depuis la page/update-checkde l'app générée, confirmant queAppUpdateServicefonctionne aussi. -
/,/license-activation, et/update-checkont tous retourné HTTP 200 avec les titres de page attendus une foisAdditionalAssemblies/AddAdditionalAssembliescâblés dansRoutes.razor/Program.cspour qu'ASP.NET Core découvre les composants routés par@pagevivant dans l'assemblyAuthFlow.AppKitréférencé (un bug d'intégration réel et non évident, détecté uniquement par ce run réel, pas pardotnet buildseul).
-
- Les artefacts de test (
dotnet new installtemporaire, dossierTestAppgénéré) ont été nettoyés ensuite.
- Hypothèse de déploiement mono-tenant : une instance serveur/processus par client, donc le store de licence est un simple fichier plat, pas une ligne de base de données par tenant.
-
Dépendance à Radzen.Blazor : les composants Razor extraits utilisent
Radzen (
RadzenIcon,RadzenButton,RadzenAlert, etc.) - c'est une dépendance de package explicite deAuthFlow.AppKit. Confirmé avec le client : la plupart de ses apps utilisent déjà Radzen, donc ça reste une dépendance dure (pas rendue optionnelle) - gardé simple volontairement. -
Pattern de repo de releases public recommandé : ne pas distribuer de
token GitHub aux machines clientes juste pour télécharger les installeurs.
Créez un second repo public, sans code, par app (ex.
MyNewApp-releases) et pointez la variableRELEASES_REPOdu workflow de release dessus - les téléchargements deviennent alors entièrement anonymes. Le chemin authentifié via l'API GitHub d'AppUpdateServicen'est qu'un fallback défensif, pour le cas (déconseillé) d'un repo de releases privé.
Ces 3 packages sont volontairement génériques et ne contiennent aucune donnée propre à un client ou à un produit réel :
- Aucun
ProductId,licenseKey, ou clé publique de signature réels codés en dur -appsettings.jsondu template a ces champs vides/à remplir par le développeur qui génère l'app. - La seule URL en dur est
https://auth-flow-dun.vercel.app, l'endpoint public de la plateforme SaaS AuthFlow elle-même (pas un secret) - c'est l'équivalent de documenter l'URL d'une API publique. - La logique de vérification de signature Ed25519/validation de licence est un algorithme générique (basé sur des clés publiques fournies en config) - la sécurité du système ne repose jamais sur le secret du code du SDK, mais sur la clé privée de signature qui ne quitte jamais le serveur AuthFlow.
Ce qui reste privé (ne va jamais sur nuget.org) : le code source du
serveur AuthFlow lui-même (Brackford-0brien/AuthFlow, la partie plateforme/
API, pas le dossier SDK), les vraies licences/clients/ProductId de chaque
client, et le code source métier des apps clientes (FneManuelInvoiceApp,
RadissonConnect, etc.) qui consomment ces packages.