fix blazor samples (#1742)

* fix blazor samples

* fixed blazor client project

* tests now use a constant

* fix wireup
This commit is contained in:
Erwin van der Valk 2025-02-04 10:37:02 +01:00 committed by GitHub
parent 53b57ff304
commit 39abeb8bf5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 107 additions and 53 deletions

View file

@ -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

View file

@ -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

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
@ -8,6 +8,9 @@
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" />

View file

@ -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();

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
@ -15,6 +15,10 @@
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Hosts.ServiceDefaults\Hosts.ServiceDefaults.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\migrations\UserSessionDb\UserSessionDb.csproj" />
<ProjectReference Include="..\Apis\Api.DPoP\Api.DPoP.csproj" />

View file

@ -1,47 +1,56 @@
using Hosts.ServiceDefaults;
using Projects;
var builder = DistributedApplication.CreateBuilder(args);
var idServer = builder.AddProject<Projects.IdentityServer>("identity-server");
var idServer = builder.AddProject<Projects.IdentityServer>(AppHostServices.IdentityServer);
var api = builder.AddProject<Projects.Api>("api");
var isolatedApi = builder.AddProject<Projects.Api_Isolated>("api-isolated");
var api = builder.AddProject<Projects.Api>(AppHostServices.Api);
var isolatedApi = builder.AddProject<Projects.Api_Isolated>(AppHostServices.IsolatedApi);
var bff = builder.AddProject<Projects.Bff>("bff")
var bff = builder.AddProject<Projects.Bff>(AppHostServices.Bff)
.WithExternalHttpEndpoints()
.WithAwaitedReference(idServer)
.WithAwaitedReference(isolatedApi)
.WithAwaitedReference(api)
;
builder.AddProject<Projects.Bff_EF>("bff-ef")
var bffEf = builder.AddProject<Projects.Bff_EF>(AppHostServices.BffEf)
.WithExternalHttpEndpoints()
.WithAwaitedReference(idServer)
.WithAwaitedReference(isolatedApi)
.WithAwaitedReference(api);
builder.AddProject<Projects.WebAssembly>("bff-webassembly-per-component")
var bffBlazorWebAssembly = builder.AddProject<Projects.WebAssembly>(AppHostServices.BffBlazorWebassembly)
.WithExternalHttpEndpoints()
.WithAwaitedReference(idServer)
.WithAwaitedReference(isolatedApi)
.WithAwaitedReference(api);
builder.AddProject<Projects.PerComponent>("bff-blazor-per-component")
var bffBlazorPerComponent = builder.AddProject<Projects.PerComponent>(AppHostServices.BffBlazorPerComponent)
.WithExternalHttpEndpoints()
.WithAwaitedReference(idServer)
.WithAwaitedReference(isolatedApi)
.WithAwaitedReference(api);
var apiDPop = builder.AddProject<Projects.Api_DPoP>("api-dpop");
var apiDPop = builder.AddProject<Projects.Api_DPoP>(AppHostServices.ApiDpop);
builder.AddProject<Projects.Bff_DPoP>("bff-dpop")
var bffDPop = builder.AddProject<Projects.Bff_DPoP>(AppHostServices.BffDpop)
.WithExternalHttpEndpoints()
.WithAwaitedReference(idServer)
.WithAwaitedReference(apiDPop);
builder.AddProject<Projects.UserSessionDb>("migrations");
builder.AddProject<Projects.UserSessionDb>(AppHostServices.Migrations);
idServer.WithReference(bff);
idServer
.WithReference(bff)
.WithReference(bffEf)
.WithReference(bffBlazorPerComponent)
.WithReference(bffBlazorWebAssembly)
.WithReference(apiDPop)
.WithReference(bffDPop)
;
builder.Build().Run();

View file

@ -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
];
}

View file

@ -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);

View file

@ -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<string> GetUrlAsync(string serviceName)
{
return (await resolver.GetEndpointsAsync("https://" + serviceName, CancellationToken.None)).Endpoints.First().EndPoint.ToString();
}
public async Task<Client> FindClientByIdAsync(string clientId)
{