From 39abeb8bf5b3ff9375946e7d9f5b6b7ad30ac60f Mon Sep 17 00:00:00 2001 From: Erwin van der Valk Date: Tue, 4 Feb 2025 10:37:02 +0100 Subject: [PATCH] fix blazor samples (#1742) * fix blazor samples * fixed blazor client project * tests now use a constant * fix wireup --- bff/.editorconfig | 1 - bff/samples/Bff/Extensions.cs | 3 +- .../PerComponent.Client.csproj | 5 ++- .../WebAssembly/WebAssembly.Client/Program.cs | 8 ++++ .../Hosts.AppHost/Hosts.AppHost.csproj | 6 ++- bff/samples/Hosts.AppHost/Program.cs | 33 ++++++++++------ .../Hosts.ServiceDefaults/AppHostServices.cs | 34 +++++++++++++++++ .../Hosts.Tests/TestInfra/AppHostFixture.cs | 38 ++++++------------- .../ServiceDiscoveringClientStore.cs | 32 ++++++++++------ 9 files changed, 107 insertions(+), 53 deletions(-) create mode 100644 bff/samples/Hosts.ServiceDefaults/AppHostServices.cs diff --git a/bff/.editorconfig b/bff/.editorconfig index ad61ea383..3eb51c72a 100644 --- a/bff/.editorconfig +++ b/bff/.editorconfig @@ -148,7 +148,6 @@ csharp_preserve_single_line_statements=true csharp_style_namespace_declarations=file_scoped:silent [*] -charset=utf-8 end_of_line=lf trim_trailing_whitespace=false insert_final_newline=false diff --git a/bff/samples/Bff/Extensions.cs b/bff/samples/Bff/Extensions.cs index b81b9a7b2..11dffe534 100644 --- a/bff/samples/Bff/Extensions.cs +++ b/bff/samples/Bff/Extensions.cs @@ -5,6 +5,7 @@ using System; using System.Threading; using Duende.Bff; using Duende.Bff.Yarp; +using Hosts.ServiceDefaults; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -58,7 +59,7 @@ internal static class Extensions // Normally, here you simply configure the authority. But here we want to // use service discovery, because aspire can change the url's at run-time. // So, it needs to be discovered at runtime. - var authority = DiscoverAuthorityByName(getServiceProvider, "identity-server"); + var authority = DiscoverAuthorityByName(getServiceProvider, AppHostServices.IdentityServer); options.Authority = authority; // confidential client using code flow + PKCE diff --git a/bff/samples/Blazor/PerComponent/PerComponent.Client/PerComponent.Client.csproj b/bff/samples/Blazor/PerComponent/PerComponent.Client/PerComponent.Client.csproj index 76baf2723..fe2ed8f9d 100644 --- a/bff/samples/Blazor/PerComponent/PerComponent.Client/PerComponent.Client.csproj +++ b/bff/samples/Blazor/PerComponent/PerComponent.Client/PerComponent.Client.csproj @@ -1,4 +1,4 @@ - + net9.0 @@ -8,6 +8,9 @@ Default + + + diff --git a/bff/samples/Blazor/WebAssembly/WebAssembly.Client/Program.cs b/bff/samples/Blazor/WebAssembly/WebAssembly.Client/Program.cs index 1348424d1..5f217dfe4 100644 --- a/bff/samples/Blazor/WebAssembly/WebAssembly.Client/Program.cs +++ b/bff/samples/Blazor/WebAssembly/WebAssembly.Client/Program.cs @@ -3,8 +3,16 @@ using Microsoft.AspNetCore.Components.WebAssembly.Hosting; var builder = WebAssemblyHostBuilder.CreateDefault(args); + builder.Services .AddBffBlazorClient() // Provides auth state provider that polls the /bff/user endpoint .AddCascadingAuthenticationState(); +builder.Services.AddScoped(sp => + new HttpClient + { + BaseAddress = new Uri(builder.HostEnvironment.BaseAddress), + DefaultRequestHeaders = { {"x-csrf", "1" }} + }); + await builder.Build().RunAsync(); diff --git a/bff/samples/Hosts.AppHost/Hosts.AppHost.csproj b/bff/samples/Hosts.AppHost/Hosts.AppHost.csproj index 0b4c8a7b6..6949be189 100644 --- a/bff/samples/Hosts.AppHost/Hosts.AppHost.csproj +++ b/bff/samples/Hosts.AppHost/Hosts.AppHost.csproj @@ -1,4 +1,4 @@ - + @@ -15,6 +15,10 @@ + + + + diff --git a/bff/samples/Hosts.AppHost/Program.cs b/bff/samples/Hosts.AppHost/Program.cs index cdd92bd37..525e21d17 100644 --- a/bff/samples/Hosts.AppHost/Program.cs +++ b/bff/samples/Hosts.AppHost/Program.cs @@ -1,47 +1,56 @@ +using Hosts.ServiceDefaults; +using Projects; + var builder = DistributedApplication.CreateBuilder(args); -var idServer = builder.AddProject("identity-server"); +var idServer = builder.AddProject(AppHostServices.IdentityServer); -var api = builder.AddProject("api"); -var isolatedApi = builder.AddProject("api-isolated"); +var api = builder.AddProject(AppHostServices.Api); +var isolatedApi = builder.AddProject(AppHostServices.IsolatedApi); -var bff = builder.AddProject("bff") +var bff = builder.AddProject(AppHostServices.Bff) .WithExternalHttpEndpoints() .WithAwaitedReference(idServer) .WithAwaitedReference(isolatedApi) .WithAwaitedReference(api) ; -builder.AddProject("bff-ef") +var bffEf = builder.AddProject(AppHostServices.BffEf) .WithExternalHttpEndpoints() .WithAwaitedReference(idServer) .WithAwaitedReference(isolatedApi) .WithAwaitedReference(api); -builder.AddProject("bff-webassembly-per-component") +var bffBlazorWebAssembly = builder.AddProject(AppHostServices.BffBlazorWebassembly) .WithExternalHttpEndpoints() .WithAwaitedReference(idServer) .WithAwaitedReference(isolatedApi) .WithAwaitedReference(api); - -builder.AddProject("bff-blazor-per-component") +var bffBlazorPerComponent = builder.AddProject(AppHostServices.BffBlazorPerComponent) .WithExternalHttpEndpoints() .WithAwaitedReference(idServer) .WithAwaitedReference(isolatedApi) .WithAwaitedReference(api); -var apiDPop = builder.AddProject("api-dpop"); +var apiDPop = builder.AddProject(AppHostServices.ApiDpop); -builder.AddProject("bff-dpop") +var bffDPop = builder.AddProject(AppHostServices.BffDpop) .WithExternalHttpEndpoints() .WithAwaitedReference(idServer) .WithAwaitedReference(apiDPop); -builder.AddProject("migrations"); +builder.AddProject(AppHostServices.Migrations); -idServer.WithReference(bff); +idServer + .WithReference(bff) + .WithReference(bffEf) + .WithReference(bffBlazorPerComponent) + .WithReference(bffBlazorWebAssembly) + .WithReference(apiDPop) + .WithReference(bffDPop) + ; builder.Build().Run(); diff --git a/bff/samples/Hosts.ServiceDefaults/AppHostServices.cs b/bff/samples/Hosts.ServiceDefaults/AppHostServices.cs new file mode 100644 index 000000000..f8168c792 --- /dev/null +++ b/bff/samples/Hosts.ServiceDefaults/AppHostServices.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hosts.ServiceDefaults; +public static class AppHostServices +{ + public const string IdentityServer = "identity-server"; + public const string Api = "api"; + public const string IsolatedApi = "api-isolated"; + public const string Bff = "bff"; + public const string BffEf = "bff-ef"; + public const string BffBlazorWebassembly = "bff-blazor-webassembly"; + public const string BffBlazorPerComponent = "bff-blazor-per-component"; + public const string ApiDpop = "api-dpop"; + public const string BffDpop = "bff-dpop"; + public const string Migrations = "migrations"; + + public static string[] All => [ + IdentityServer, + Api, + IsolatedApi, + Bff, + BffEf, + BffBlazorWebassembly, + BffBlazorPerComponent, + ApiDpop, + BffDpop, + Migrations + ]; + +} diff --git a/bff/samples/Hosts.Tests/TestInfra/AppHostFixture.cs b/bff/samples/Hosts.Tests/TestInfra/AppHostFixture.cs index 9216ad94c..81fbe56d8 100644 --- a/bff/samples/Hosts.Tests/TestInfra/AppHostFixture.cs +++ b/bff/samples/Hosts.Tests/TestInfra/AppHostFixture.cs @@ -1,4 +1,5 @@ using Aspire.Hosting; +using Hosts.ServiceDefaults; using Microsoft.Extensions.Logging; #if !DEBUG_NCRUNCH @@ -81,33 +82,16 @@ public class AppHostFixture : IAsyncLifetime await (await appHost.BuildAsync()).StartAsync(); // Wait for all the services so that their logs are mostly written. - await resourceNotificationService.WaitForResourceAsync( - "bff", - KnownResourceStates.Running - ) - .WaitAsync(TimeSpan.FromSeconds(30)); - await resourceNotificationService.WaitForResourceAsync( - "bff-ef", - KnownResourceStates.Running - ) - .WaitAsync(TimeSpan.FromSeconds(30)); + foreach (var resource in AppHostServices.All) + { + await resourceNotificationService.WaitForResourceAsync( + resource, + KnownResourceStates.Running + ) + .WaitAsync(TimeSpan.FromSeconds(30)); + } - await resourceNotificationService.WaitForResourceAsync( - "bff-webassembly-per-component", - KnownResourceStates.Running - ) - .WaitAsync(TimeSpan.FromSeconds(30)); - await resourceNotificationService.WaitForResourceAsync( - "bff-dpop", - KnownResourceStates.Running - ) - .WaitAsync(TimeSpan.FromSeconds(30)); - await resourceNotificationService.WaitForResourceAsync( - "migrations", - KnownResourceStates.Running - ) - .WaitAsync(TimeSpan.FromSeconds(30)); #endif //#DEBUG_NCRUNCH } @@ -166,7 +150,9 @@ public class AppHostFixture : IAsyncLifetime // so build a http client that directly points to this host. var url = clientName switch { - "bff" => "https://localhost:5002", + AppHostServices.Bff => "https://localhost:5002", + AppHostServices.BffBlazorPerComponent => "https://localhost:5105", + AppHostServices.BffBlazorWebassembly => "https://localhost:5005", _ => throw new InvalidOperationException("client not configured") }; baseAddress = new Uri(url); diff --git a/bff/samples/IdentityServer/ServiceDiscoveringClientStore.cs b/bff/samples/IdentityServer/ServiceDiscoveringClientStore.cs index e3befdbd5..928c41213 100644 --- a/bff/samples/IdentityServer/ServiceDiscoveringClientStore.cs +++ b/bff/samples/IdentityServer/ServiceDiscoveringClientStore.cs @@ -1,9 +1,10 @@ -// // Copyright (c) Duende Software. All rights reserved. +// // Copyright (c) Duende Software. All rights reserved. // // See LICENSE in the project root for license information. using Duende.IdentityModel; using Duende.IdentityServer.Models; using Duende.IdentityServer.Stores; +using Hosts.ServiceDefaults; using Microsoft.Extensions.ServiceDiscovery; namespace IdentityServer; @@ -32,7 +33,11 @@ public class ServiceDiscoveringClientStore(ServiceEndpointResolver resolver) : I return; } // Get the BFF URL from the service discovery system. Then use this for building the redirect urls etc.. - var bffUrl = (await resolver.GetEndpointsAsync("https://bff", CancellationToken.None)).Endpoints.First().EndPoint.ToString(); + var bffUrl = await GetUrlAsync(AppHostServices.Bff); + var bffDPopUrl = await GetUrlAsync(AppHostServices.BffDpop); + var bffEfUrl = await GetUrlAsync(AppHostServices.BffEf); + var bffBlazorPerComponentUrl = await GetUrlAsync(AppHostServices.BffBlazorPerComponent); + var bffBlazorWebAssemblyUrl = await GetUrlAsync(AppHostServices.BffBlazorWebassembly); _clients = [ new Client @@ -69,9 +74,9 @@ public class ServiceDiscoveringClientStore(ServiceEndpointResolver resolver) : I OidcConstants.GrantTypes.TokenExchange }, - RedirectUris = { "https://localhost:5003/signin-oidc" }, - FrontChannelLogoutUri = "https://localhost:5003/signout-oidc", - PostLogoutRedirectUris = { "https://localhost:5003/signout-callback-oidc" }, + RedirectUris = { $"{bffDPopUrl}signin-oidc" }, + FrontChannelLogoutUri = $"{bffDPopUrl}signout-oidc", + PostLogoutRedirectUris = { $"{bffDPopUrl}signout-callback-oidc" }, AllowOfflineAccess = true, AllowedScopes = { "openid", "profile", "api", "scope-for-isolated-api" }, @@ -89,10 +94,10 @@ public class ServiceDiscoveringClientStore(ServiceEndpointResolver resolver) : I GrantType.ClientCredentials, OidcConstants.GrantTypes.TokenExchange }, - RedirectUris = { "https://localhost:5004/signin-oidc" }, - FrontChannelLogoutUri = "https://localhost:5004/signout-oidc", - BackChannelLogoutUri = "https://localhost:5004/bff/backchannel", - PostLogoutRedirectUris = { "https://localhost:5004/signout-callback-oidc" }, + RedirectUris = { $"{bffEfUrl}signin-oidc" }, + FrontChannelLogoutUri = $"{bffEfUrl}signout-oidc", + BackChannelLogoutUri = $"{bffEfUrl}bff/backchannel", + PostLogoutRedirectUris = { $"{bffEfUrl}signout-callback-oidc" }, AllowOfflineAccess = true, AllowedScopes = { "openid", "profile", "api", "scope-for-isolated-api" }, @@ -112,10 +117,10 @@ public class ServiceDiscoveringClientStore(ServiceEndpointResolver resolver) : I OidcConstants.GrantTypes.TokenExchange }, - RedirectUris = { "https://localhost:5005/signin-oidc", "https://localhost:5105/signin-oidc" }, + RedirectUris = { $"{bffBlazorWebAssemblyUrl}signin-oidc", $"{bffBlazorPerComponentUrl}signin-oidc" }, PostLogoutRedirectUris = { - "https://localhost:5005/signout-callback-oidc", "https://localhost:5105/signout-callback-oidc" + $"{bffBlazorWebAssemblyUrl}signout-callback-oidc", $"{bffBlazorPerComponentUrl}signout-callback-oidc" }, AllowOfflineAccess = true, @@ -132,6 +137,11 @@ public class ServiceDiscoveringClientStore(ServiceEndpointResolver resolver) : I } + private async Task GetUrlAsync(string serviceName) + { + return (await resolver.GetEndpointsAsync("https://" + serviceName, CancellationToken.None)).Endpoints.First().EndPoint.ToString(); + } + public async Task FindClientByIdAsync(string clientId) {