OpenIddict vise à fournir une solution polyvalente pour mettre en œuvre un client et un serveur OpenID Connect pour supporter la validation de jeton JWT dans n'importe quelle application .NET. Je décrirai dans cet article les étapes à suivre pour réaliser un cas d'utilisation simple.
J’avais besoin de créer une application RESTFul simple permettant de simuler un service web fourni par un client, mais inaccessible depuis mon environnement pour des raisons de sécurité.
De plus, certains points d’accès seraient interrogés via l’authentification de base et d’autres via le standard OpenID OAuth2.
Ce ne fut pas très simple, car, en même temps, je me débattais avec :
Trouver les logs de l’application dans mon App Service pour déboguer le déploiement vers Azure.
Ajouter les bons liens entre les ressources avec des permissions très limitées dans mon organisation.
Une instance SQL Server pour créer une nouvelle base de données. Toutefois vous pouvez sûrement utiliser un autre type de base de données, comme MySQL ou Postgresql. Vous en avez besoin pour la base de données OpenIddict où vous stockez les applications autorisées et les jetons. Vous pouvez également utiliser une base de données SQLite. Personnellement, j’avais déjà un serveur SQL provisionné.
Créer la base de données openiddict.
Je vais utiliser un serveur SQL pour héberger les données de OpenIddict. Comme indiqué ci-dessus, vous pouvez choisir un autre pilote.
Vous devrez le provisionner avant de continuer.
Voici les étapes à suivre :
Naviguez sur le portail Azure.
Recherchez et sélectionnez SQL Databases (Bases de données SQL) dans la bar de recherche.
Cliquez sur Create (Créer).
Note : si vous n’avez pas encore d’instance SQL, le portail Azure vous demandera de la créer. Utilisez SQL authentication pour créer les informations d’identification permettant de se connecter l’instance sur SQL Server Management Studio (en abrégé SSMS) et depuis l’application que nous allons créer.
Sous l’onglet Basics
Assurez-vous de sélectionner le Subscription et le Ressource Group
Définissez le nom de la base de données à openiddict.
Définissez l’instance du serveur (ou créez-en une).
Laissez Want to use SQL elastic pool à No.
Laissez Workload environment à Development.
Configurez le Compute + storage à Basic tier avec 500 MB Storage.
Choisissez Sauvegarde localement redondante.
Sous l’onglet Networking
Laisser les valeurs par défaut telles quelles.
Sous l’onglet Security
Laisser les valeurs par défaut telles quelles.
Sous l’onglet Additional settings
Choisissez la Collation à French_CI_AS ou la valeur que vous souhaitez.
Laisser les autres valeurs telles quelles.
Sous l’onglet Tags
Ajoutez les étiquettes nécessaires.
Sous l’onglet Review + create
Vérifiez le résumé et cliquez sur Create.
Modifier le Program.cs pour utiliser SQL Server
Tout d’abord, ajoutez les paquets nuget ci-dessous :
usingDemoWebApiWithOpenIddict.Models;usingMicrosoft.EntityFrameworkCore;usingMicrosoft.IdentityModel.Protocols.Configuration;usingvarloggerFactory=LoggerFactory.Create(loggingBuilder=>loggingBuilder.SetMinimumLevel(LogLevel.Trace).AddConsole());ILoggerlogger=loggerFactory.CreateLogger<Program>();logger.LogInformation("Program.cs logger ready :)");logger.LogInformation("Program.cs > init builder...");builder.Services.AddControllers();builder.Services.AddDbContext<ApplicationDbContext>(options=>{// Configurer le contexte pour utiliser le serveur SQL.vardbServer=RetrieveValueFromConfig(builder,"DbServer",logger);vardbUser=RetrieveValueFromConfig(builder,"DbUser",logger);vardbPassword=RetrieveValueFromConfig(builder,"DbPassword",logger);varconnectionString=builder.Configuration.GetConnectionString("DefaultConnection")!;options.UseSqlServer(string.Format(connectionString,dbServer,dbUser,dbPassword));// Enregistrer les ensembles d'entités nécessaires à OpenIddict.options.UseOpenIddict();});staticstringRetrieveValueFromConfig(WebApplicationBuilderbuilder,stringkey,ILoggerlogger){varkeyValue=builder.Configuration[key];returnkeyValue??thrownewConfigurationErrorsException($"Missing <{key}> environment value in App Service");}
Vous devez déclarer le ConnectionString dans votre appsettings.json.
Sur la ressource App Service, nous devons ajouter les 3 variables ci-dessus sous la lame Environment variables du App Service.
Cliquez sur « + Add » pour chaque variable et fournissez son nom et sa valeur tels que définis dans le fichier JSON. Par défaut, je coche la case « Deployment slot setting » pour m’assurer que Microsoft Azure utilise le paramètre lors de la création d’un slot (un autre sujet en soi dont je parlerai un jour).
Pour tester, nous aurons besoin de compléter quelques étapes supplémentaires.
Note : vous pouvez stocker la ConnectionString dans un KeyVault. J’ai choisi les variables d’environnement pour stocker le serveur, l’utilisateur et le mot de passe pour des raisons de simplicité.
Le Key Vault
Pourquoi un Key Vault
Pour protéger les jetons générés, le client et le serveur d’OpenIddict utilisent deux types d’informations d’identification :
Les identifiants de signature, utilisés pour se protéger contre la falsification.
Les identifiants de chiffrement, utilisés pour s’assurer que le contenu des jetons ne peut pas être lu par des utilisateurs ou applications malveillants.
Lire les certificats depuis l’application dans Azure.
Pour générer les certificats, vous avez besoin d’une politique d’accès. En fonction de votre ancienneté dans votre organisation, vous pouvez ne pas avoir la permission de lister les utilisateurs ou les applications auxquels vous devez assigner la politique d’accès.
Donc, tout d’abord, sous le Key Vault nouvellement créé, sélectionnez la lame Access Policies et cliquez sur « + Create ».
Nous allons ajouter la politique d’accès au créateur du certificat (vous), donc si vous n’arrivez pas à valider la création, demandez à votre manager.
Dans le formulaire,
Sélectionnez Select all comme Permissions.
Ensuite, sélectionnez le Principal ou l’utilisateur en utilisant votre adresse email complète.
Laissez le champ Application vide.
Terminez en cliquant sur Create.
Ensuite, ajoutez une autre politique d’accès à la ressource App Service.
Avant cela, assurez-vous d’activer l’identité System assigned sous le App Service et la lame Identity. Cela va générer un Principal (Object) ID que vous utiliserez pour rechercher le Principal ou « utilisateur » auquel assigner la politique d’accès.
Pour cette politique d’accès, assignez uniquement les permissions « Get » et « List ».
Juste au cas où
Alors que je faisais cela moi-même pour la première fois, j’ai pensé que je devais ajouter des permissions basées sur les rôles pour moi-même et le App Service :
Key Vault Administrator assigné à moi-même.
Key Vault Cerfitificates User et Key Vault Cerfitificates Officer à la ressource App Service.
Je ne pense pas que vous en ayez besoin. Mais juste au cas où les politiques d’accès…
Générer les certificats
Naviguez maintenant vers la lame Certificates dans votre Key Vault et :
Cliquez sur « + Generate/Import ».
Laissez la méthode à « Generate._ ».
Donnez un nom comme « certificate-openiddict-encryption ».
Laissez le type de certificat à Self-signed certificate à moins que vous ne puissiez fournir une autorité.
Définissez le Subject comme étant le nom de domaine complet de votre App Service. Vous pourriez donc avoir par exemple CN=votre-appservice-fcg3bqdgbme3dchd.westeurope-01.azurewebsites.net_. Veuillez adapter l’URI à l’URI de votre service d’application.
Choisissez la Validity Period.
Laissez le Lifetime Action Type tel qu’il est, par exemple, Automatically renew at a given percentage lifetime.
Confirmez en cliquant sur Create.
Répétez les étapes, mais nommez le second certificat « certificate-openiddict-signing ».
Intégrer la solution OpenIddict pour activer OpenID sur le projet
De retour au Program.cs, nous ajoutons d’abord les paquets nécessaires :
usingSystem.Security.Cryptography.X509Certificates;staticvoidSetupOpenIddict(WebApplicationBuilderbuilder,ILoggerlogger){builder.Services.AddOpenIddict().AddCore(options=>{// Configurer OpenIddict pour utiliser les magasins et modèles Entity Framework Core.// Note : appeler ReplaceDefaultEntities() pour remplacer les entités par défaut d'OpenIddict.options.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>();})// Enregistrer les composants du serveur OpenIddict..AddServer(options=>{// Et activer le point de terminaison du jeton.options.SetTokenEndpointUris("connect/token");// Ensuite, activez le flux `client credentials`.options.AllowClientCredentialsFlow();// Ensuite, définissez les certificats.if(builder.Environment.IsDevelopment()){// En local, utiliser les certificats fournis par OpenIddict.// Ils ne fonctionneront pas en production.options.AddDevelopmentEncryptionCertificate().AddDevelopmentSigningCertificate();}else{// En production, utiliser les certificats lus depuis le Key Vault.logger.LogInformation("SetupOpenIddict > AddServer > Not Development...");string?keyVaultUri=RetrieveValueFromConfig(builder,"OpenIddict:KeyVaultUri",logger);logger.LogInformation($"SetupOpenIddict > AddServer > OpenIddict:KeyVaultUri is <{keyVaultUri}>");// Initialiser le client de certificat pour lire dans le Key Vault.varcertClient=newCertificateClient(newUri(keyVaultUri),newDefaultAzureCredential());logger.LogInformation("SetupOpenIddict > AddServer > KeyValult client to read certificates = OK!");// Lire le certificat de chiffrementvaropenIddict_EncryptionCertificateName=RetrieveValueFromConfig(builder,"OpenIddict:EncryptionCertificateName",logger);logger.LogInformation($"SetupOpenIddict > AddServer > OpenIddict:EncryptionCertificateName is <{openIddict_EncryptionCertificateName}>");try{// Télécharger le certificat complet qui inclut la clé privée,// nécessaire pour OpenIddict.//GetCertificate n'est pas suffisant et ne contient pas la clé privée du certificat, nécessaire à `AddEncryptionCertificate`.varencryptionCert=certClient.DownloadCertificate(openIddict_EncryptionCertificateName).Value;logger.LogInformation($"SetupOpenIddict > AddServer > read encryption cert: <{encryptionCert}>");options.AddEncryptionCertificate(newX509Certificate2(encryptionCert));logger.LogInformation("SetupOpenIddict > AddServer > AddEncryptionCertificate = OK!");}catch(Exceptionex){logger.LogError(ex.Message,ex.StackTrace);throw;}// Lire le certificat de signaturevaropenIddict_SigningCertificateName=RetrieveValueFromConfig(builder,"OpenIddict:SigningCertificateName",logger);logger.LogInformation($"SetupOpenIddict > AddServer > OpenIddict:SigningCertificateName is <{openIddict_SigningCertificateName}>");try{varsigningCert=certClient.DownloadCertificate(openIddict_SigningCertificateName).Value;logger.LogInformation($"SetupOpenIddict > AddServer > read encryption cert: <{signingCert}>");options.AddSigningCertificate(newX509Certificate2(signingCert));logger.LogInformation("SetupOpenIddict > AddServer > AddSigningCertificate = OK!");}catch(Exception){throw;}}// Enregistrer l'hôte ASP.NET Core et// configurer les options spécifiques à ASP.NET Core.options.UseAspNetCore().EnableTokenEndpointPassthrough();})// Enregistrer les composants de validation d'OpenIddict..AddValidation(options=>{// Importer la configuration depuis l'instance locale d'OpenIddict// Fondamentalement, IIS Express ou la ressource App Service est le serveur OpenID qui tourne en parallèle de votre API Web.options.UseLocalServer();// Enregistrer l'hôte ASP.NET Core.options.UseAspNetCore();});}
Vous avez peut-être remarqué que vous devez définir quelques clés de configuration dans appsettings.json. Les voici :
1
2
3
4
5
6
7
8
9
{// ... le reste du fichier
"OpenIddict":{"KeyVaultUri":"https://kcdemo.vault.azure.net/","EncryptionCertificateName":"certificat-openiddict-encryption","SigningCertificateName":"certificat-openiddict-signing"}// ... le reste du fichier
}
Les noms des certificats sont importants. Ils doivent correspondre au nom fourni lors de la création du certificat.
Ensuite, vous pouvez définir les valeurs des variables d’environnement. Pour ce faire, ajustez les clés de configuration et la façon dont vous les lisez dans le code (OpenIddict:KeyVaultUri vs OpenIddict_KeyVaultUri) :
1
2
3
4
5
6
7
{// ... le reste du fichier
"OpenIddict_KeyVaultUri":"https://kcdemo.vault.azure.net/","OpenIddict_EncryptionCertificateName":"certificat-openiddict-encryption","OpenIddict_SigningCertificateName":"certificat-openiddict-signing"// ... le reste du fichier
}
Alimenter la base de données avec l’enregistrement d’une application de démonstration
Pour pouvoir tester plus tard, nous devons informer OpenIddict qui peut s’authentifier et obtenir des jetons.
Pour ce faire, créons un fichier Seeder.cs à la racine du projet WebApi :
usingSystem;usingSystem.Threading;usingSystem.Threading.Tasks;usingDemoWebApiWithOpenIddict.Models;usingMicrosoft.Extensions.DependencyInjection;usingMicrosoft.Extensions.Hosting;usingOpenIddict.Abstractions;usingstaticOpenIddict.Abstractions.OpenIddictConstants;namespaceDemoWebApiWithOpenIddict.Core;publicclassOpenIddictSeeder:IHostedService{privatereadonlyIServiceProvider_serviceProvider;publicOpenIddictSeeder(IServiceProviderserviceProvider)=>_serviceProvider=serviceProvider;publicasyncTaskStartAsync(CancellationTokencancellationToken){awaitusingvarscope=_serviceProvider.CreateAsyncScope();varcontext=scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();awaitcontext.Database.EnsureCreatedAsync();varmanager=scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();varapplication=awaitmanager.FindByClientIdAsync("console");if(application==null){awaitCreateApplication(manager);}else{awaitmanager.DeleteAsync(application);awaitCreateApplication(manager);}}privatestaticasyncTaskCreateApplication(IOpenIddictApplicationManagermanager){awaitmanager.CreateAsync(newOpenIddictApplicationDescriptor{// Le ClientId et le ClientSecret seront utilisés dans le client plus loin dans l'article.ClientId="console",ClientSecret="388D45FA-B36B-4988-BA59-B187D329C207",DisplayName="Demo OAuth2 App For RefList",Permissions={Permissions.Endpoints.Token,Permissions.GrantTypes.ClientCredentials}});}publicTaskStopAsync(CancellationTokencancellationToken)=>Task.CompletedTask;}
Note : Le ClientSecret est un GUID aléatoire.
D’ailleurs, le ClientSecret doit être :
Suffisamment aléatoire et impossible à deviner.
Généré à l’aide d’une méthode cryptographique sûre.
D’une longueur d’au moins 256 bits, généralement représentée par une chaîne hexadécimale de 64 caractères.
Ensuite, instruisez l’application dans Program.cs de l’exécuter juste avant builder.Build() :
1
2
3
4
logger.LogInformation("Program.cs > Seed the OpenIddict database.");builder.Services.AddHostedService<OpenIddictSeeder>();varapp=builder.Build();
Créer le fichier de migration
Cette étape permet de créer les tables de la base de données pour OpenIddict dans la base de données créée précédemment. Vous devez d’abord installer le paquet suivant :
# Positionnez-vous dans votre projet, si vous êtes dans une grande solution.cd DemoWebApiWithOpenIddict# Créer ensuite la migrationdotnetefmigrationsaddInitOpenIddict--contextDemoWebApiWithOpenIddict.Models.ApplicationDbContext--output-dir./Migrations# Et créer le fichier SQL à exécuter manuellement ou via DbUp, si vous l'utilisez.# Le « 0 » signifie que nous demandons de générer la première migration.# L'option « -i » indique à EF de générer un script que vous pouvez exécuter plusieurs fois (par exemple, réinitialisation).dotnetefmigrationsscript0InitOpenIddict--contextDemoWebApiWithOpenIddict.Models.ApplicationDbContext-o./SQL/Patch/001-init-openiddict-tables.sql-i
Juste au cas où, éditez le .csproj pour avoir ce qui suit si les commandes de migration échouent :
Ouvrez SSMS et connectez-vous à votre instance SQL et sélectionnez la base de données openiddict.
Ouvrez le script 001-init-openiddict-tables.sql du dossier SQL/Patch et exécutez-le.
Note : Vous aurez quelques avertissements. Cela ne pose pas de problème. Terminez le guide et lancez l’application.
Mettre à jour les contrôleurs
Ajouter un contrôleur AuthorizationController
Tout d’abord, vous devez activer l’authentification pour votre application : dans Program.cs, ajoutez app.UseAuthentication(); juste avant app.UseAuthorization(); .
Ensuite, dans le dossier Controllers, ajoutez ce AuthorizationController qui va générer le token lorsqu’il est demandé :
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/usingSystem.Security.Claims;usingDemoWebApiWithOpenIddict.Helpers;usingMicrosoft.AspNetCore;usingMicrosoft.AspNetCore.Mvc;usingMicrosoft.IdentityModel.Tokens;usingOpenIddict.Abstractions;usingOpenIddict.Server.AspNetCore;usingstaticOpenIddict.Abstractions.OpenIddictConstants;namespaceDemoWebApiWithOpenIddict.Controllers;publicclassAuthorizationController:Controller{privatereadonlyIOpenIddictApplicationManager_applicationManager;privatereadonlyIOpenIddictScopeManager_scopeManager;publicAuthorizationController(IOpenIddictApplicationManagerapplicationManager,IOpenIddictScopeManagerscopeManager){_applicationManager=applicationManager;_scopeManager=scopeManager;} [HttpPost("~/connect/token"), IgnoreAntiforgeryToken, Produces("application/json")]publicasyncTask<IActionResult>Exchange(){varrequest=HttpContext.GetOpenIddictServerRequest();if(request.IsClientCredentialsGrantType()){// Note : les informations d'identification du client sont automatiquement validées par OpenIddict :// si client_id ou client_secret sont invalides, cette action ne sera pas invoquée.varapplication=await_applicationManager.FindByClientIdAsync(request.ClientId);if(application==null){thrownewInvalidOperationException("The application details cannot be found in the database.");}// Créer l'identité basée sur les "claims" qui sera utilisée par OpenIddict pour générer des jetons.varidentity=newClaimsIdentity(authenticationType:TokenValidationParameters.DefaultAuthenticationType,nameType:Claims.Name,roleType:Claims.Role);// Ajouter les "claims" qui seront persistées dans les jetons (utiliser l'identifiant du client comme identifiant du sujet).identity.SetClaim(Claims.Subject,await_applicationManager.GetClientIdAsync(application));identity.SetClaim(Claims.Name,await_applicationManager.GetDisplayNameAsync(application));// Note : Dans la spécification originale d'OAuth 2.0, le client "credentials grant"// ne renvoie pas de jeton d'identité, ce qui est un concept OpenID Connect.//// En tant qu'extension non standardisée, OpenIddict permet de renvoyer un id_token// pour transmettre des informations sur l'application cliente lorsque la portée « openid » est accordée (c'est-à-dire spécifiée par l'application).// Définir la liste des champs d'application accordés à l'application cliente dans access_token.identity.SetScopes(request.GetScopes());identity.SetResources(await_scopeManager.ListResourcesAsync(identity.GetScopes()).ToListAsync());identity.SetDestinations(GetDestinations);returnSignIn(newClaimsPrincipal(identity),OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);}thrownewNotImplementedException("The specified grant type is not implemented.");}privatestaticIEnumerable<string>GetDestinations(Claimclaim){// Note : par défaut, les "clains" ne sont PAS automatiquement inclus dans les jetons d'accès et d'identité.// Pour permettre à OpenIddict de les sérialiser, vous devez leur attacher une destination, qui spécifie// si elles doivent être incluses dans les jetons d'accès, dans les jetons d'identité ou dans les deux.returnclaim.Typeswitch{Claims.NameorClaims.Subject=>[Destinations.AccessToken,Destinations.IdentityToken],_=>[Destinations.AccessToken],};}}
Important : le point de terminaison que vous avez spécifié dans le Program.cs (options.SetTokenEndpointUris) doit correspondre au point de terminaison de ce contrôleur.
Modifier le contrôleur WeatherForecast
Pour autoriser les requêtes des clients authentifiés utilisant un jeton valide, ajoutons l’attribut Authorize :
1
2
3
4
5
6
7
8
9
10
namespaceDemoWebApiWithOpenIddict.Controllers{ [Authorize(AuthenticationSchemes = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)] [ApiController] [Route("[controller]")]
publicclassWeatherForecastController:ControllerBase{// Le code de votre contrôleur}}
Vous pouvez placer l’attribut sur certaines méthodes si elles ne requièrent pas toutes une autorisation. De la même manière, vous pouvez avoir des contrôleurs qui ne requièrent aucune autorisation OAuth2.
Maintenant, lancez votre application localement : lorsque vous chargez le point de terminaison /weatherforecast, vous devriez obtenir une erreur HTTP 401. Nous nous y attendions !
Tester l’implémentation
Tester localement
Pour tester votre API Web localement, utilisez le code de l’application console ci-dessous et sélectionnez la première URL (adaptez-les à votre environnement 😉 ).
usingSystem.Net.Http.Headers;usingMicrosoft.Extensions.DependencyInjection;usingOpenIddict.Client;staticstring?PickUrl(){Console.WriteLine("Please select a URL:");Console.WriteLine("1. https://localhost:7129 (Make sure you are running it locally)");Console.WriteLine("2. https://your-app-service-efgmfncjguejeaes.westeurope-01.azurewebsites.net");while(true){Console.Write("\nEnter 1 or 2: ");stringchoice=Console.ReadLine();returnchoiceswitch{"1"=>"https://localhost:7129","2"=>"https://your-app-service-efgmfncjguejeaes.westeurope-01.azurewebsites.net",_=>null};}}varhost=PickUrl();varnoPick=host==null;varpickAttempts=0;varmaxPickAttempts=5;while(noPick){host=PickUrl();noPick=host==null;pickAttempts++;if(pickAttempts>=maxPickAttempts){Console.Write("\nFollow instructions... Restart the app :)");Console.ReadLine();}}if(host==null)return;Console.WriteLine($"\nWebApi picked: {host}");ServiceCollectionservices=ConfigureValidServices(host);awaitusingvarprovider=services.BuildServiceProvider();vartoken=awaitGetTokenAsync(provider);Console.WriteLine("Access token: {0}",token);Console.WriteLine();varresponse=awaitGetResourceAsync(provider,token,host!,"/weatherforecast");Console.WriteLine("API response: {0}",response);Console.WriteLine();Console.WriteLine("Press key to test oauth-protected endpoint");Console.ReadLine();response=awaitGetResourceAsync(provider,token,host,"/weatherforecast",false);Console.WriteLine("API response: {0}",response);Console.WriteLine();Console.WriteLine("Press key to test oauth-protected endpoint without token bearer");Console.ReadLine();staticasyncTask<string>GetTokenAsync(IServiceProviderprovider){varservice=provider.GetRequiredService<OpenIddictClientService>();varresult=awaitservice.AuthenticateWithClientCredentialsAsync(new());returnresult.AccessToken;}staticasyncTask<string>GetResourceAsync(IServiceProviderprovider,stringtoken,stringhost,stringresource,boolincludeAuthBearer=true){usingvarclient=provider.GetRequiredService<HttpClient>();usingvarrequest=newHttpRequestMessage(HttpMethod.Get,$"{host}{resource}");if(includeAuthBearer){request.Headers.Authorization=newAuthenticationHeaderValue("Bearer",token);}Console.WriteLine($"Result of calling {host}{resource}");usingvarresponse=awaitclient.SendAsync(request);try{response.EnsureSuccessStatusCode();returnawaitresponse.Content.ReadAsStringAsync();}catch(Exceptionex){Console.WriteLine(ex.Message);}finally{client.Dispose();}return"Error thrown";}staticServiceCollectionConfigureValidServices(string?host,stringscope="demo_api_scope"){varservices=newServiceCollection();services.AddOpenIddict().AddClient(options=>{options.AllowClientCredentialsFlow();options.DisableTokenStorage();options.UseSystemNetHttp().SetProductInformation(typeof(Program).Assembly);options.AddRegistration(newOpenIddictClientRegistration{Issuer=newUri($"{host}/",UriKind.Absolute),// Doit correspondre aux valeurs de OpenIddictSeederClientId="console",ClientSecret="388D45FA-B36B-4988-BA59-B187D329C207"});});returnservices;}
Test sur la ressource App Service
Enfin, appuyez sur le bouton Publish dans Visual Studio.
Assurez-vous que l’application se charge correctement et qu’aucune erreur ne s’est produite en utilisant le fichier de traces applicatives.
Lancez ensuite l’application console et choisissez l’URL distante.
Vous devriez obtenir les mêmes résultats !
Conclusion
Voilà, c’est fait ! C’était long, mais j’ai passé deux jours à le comprendre complètement (au passage, l’IA ne fait pas tout, mais elle m’a aidé).