Skip to content

Commit

Permalink
feat: prerender app
Browse files Browse the repository at this point in the history
  • Loading branch information
aguacongas committed Nov 4, 2020
1 parent b632e78 commit ccf5040
Show file tree
Hide file tree
Showing 17 changed files with 200 additions and 78 deletions.
12 changes: 10 additions & 2 deletions src/Aguacongas.TheIdServer.BlazorApp/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Project: Aguafrommars/TheIdServer
// Copyright (c) 2020 @Olivier Lefebvre
using Aguacongas.TheIdServer.BlazorApp.Models;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.JSInterop;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -16,8 +18,14 @@ public class Program
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.AddTheIdServerApp();
builder.AddTheIdServerApp();
var configuration = builder.Configuration;
var settings = configuration.Get<Settings>();
if (!settings.Prerendered)
{
builder.RootComponents.Add<App>("app");
}

var host = builder.Build();
var runtime = host.Services.GetRequiredService<IJSRuntime>();
var cultureName = await runtime.InvokeAsync<string>("localStorage.getItem", "culture").ConfigureAwait(false);
Expand Down
4 changes: 0 additions & 4 deletions src/Aguacongas.TheIdServer.BlazorApp/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,3 @@
</li>
</ul>
</div>

<div class="fixed-bottom">
<a class="px-3" href="https://github.com/aguacongas/TheIdServer/blob/master/README.md" target="_blank">About</a>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"Prerendered": true,
"administratorEmail": "[email protected]",
"apiBaseUrl": "https://localhost:5443/api",
"loggingOptions": {
Expand Down
3 changes: 3 additions & 0 deletions src/Aguacongas.TheIdServer/Aguacongas.TheIdServer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Seq" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
<Page Include="Pages\_Host.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Aguacongas.TheIdServer.Authentication\Aguacongas.TheIdServer.Authentication.csproj" />
<ProjectReference Include="..\Aguacongas.TheIdServer.BlazorApp\Aguacongas.TheIdServer.BlazorApp.csproj" />
Expand Down
42 changes: 42 additions & 0 deletions src/Aguacongas.TheIdServer/Pages/_Host.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@page
@using Aguacongas.TheIdServer.BlazorApp
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>TheIdServer Admin</title>
<base href="/" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="//code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="//stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<link href="css/app.css" rel="stylesheet" />
</head>
<body class="bg-light">
<app>
@if (!HttpContext.Request.Path.StartsWithSegments("/authentication"))
{
<component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
}
</app>

<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>

<script src="_content/Aguacongas.TheIdServer.BlazorApp.Infrastructure/TheIdServerInterop.js"></script>
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions src/Aguacongas.TheIdServer/Services/AccessTokenProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using System;
using System.Threading.Tasks;

namespace Aguacongas.TheIdServer.Services
{
public class AccessTokenProvider : IAccessTokenProvider
{
public ValueTask<AccessTokenResult> RequestAccessToken()
{
throw new NotImplementedException();
}

public ValueTask<AccessTokenResult> RequestAccessToken(AccessTokenRequestOptions options)
{
throw new NotImplementedException();
}
}
}
19 changes: 19 additions & 0 deletions src/Aguacongas.TheIdServer/Services/JSRuntime.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.JSInterop;
using System.Threading;
using System.Threading.Tasks;

namespace Aguacongas.TheIdServer.Services
{
public class JSRuntime : IJSRuntime
{
public ValueTask<TValue> InvokeAsync<TValue>(string identifier, object[] args)
{
return new ValueTask<TValue>();
}

public ValueTask<TValue> InvokeAsync<TValue>(string identifier, CancellationToken cancellationToken, object[] args)
{
return new ValueTask<TValue>();
}
}
}
49 changes: 38 additions & 11 deletions src/Aguacongas.TheIdServer/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,28 @@
using Aguacongas.AspNetCore.Authentication;
using Aguacongas.IdentityServer;
using Aguacongas.IdentityServer.Abstractions;
using Aguacongas.IdentityServer.Admin.Http.Store;
using Aguacongas.IdentityServer.Admin.Options;
using Aguacongas.IdentityServer.Admin.Services;
using Aguacongas.IdentityServer.EntityFramework.Store;
using Aguacongas.IdentityServer.Store;
using Aguacongas.TheIdServer.Admin.Hubs;
using Aguacongas.TheIdServer.Areas.Identity;
using Aguacongas.TheIdServer.BlazorApp.Models;
using Aguacongas.TheIdServer.Data;
using Aguacongas.TheIdServer.Models;
using Aguacongas.TheIdServer.Services;
using IdentityModel.AspNetCore.OAuth2Introspection;
using IdentityServer4.AccessTokenValidation;
using IdentityServer4.Quickstart.UI;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components.WebAssembly.Services;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -55,9 +64,14 @@ public void ConfigureServices(IServiceCollection services)
{
var isProxy = Configuration.GetValue<bool>("Proxy");

void configureOptions(IdentityServerOptions options)
=> Configuration.GetSection("PrivateServerAuthentication").Bind(options);

services.AddConfigurationHttpStores(configureOptions);

if (isProxy)
{
AddProxyServices(services);
AddProxyServices(services, configureOptions);
}
else
{
Expand Down Expand Up @@ -147,8 +161,18 @@ public void ConfigureServices(IServiceCollection services)
mvcBuilder.AddIdentityServerAdmin<ApplicationUser, SchemeDefinition>()
.AddEntityFrameworkStore<ConfigurationDbContext>();
}
services.AddScoped<LazyAssemblyLoader>()
.AddDatabaseDeveloperPageExceptionFilter()

services.AddScoped<LazyAssemblyLoader>()
.AddScoped<AuthenticationStateProvider, ServerAuthenticationStateProvider>()
.AddScoped<SignOutSessionStateManager>()
.AddTransient<IAccessTokenProvider, AccessTokenProvider>()
.AddTransient<Microsoft.JSInterop.IJSRuntime, JSRuntime>()
.AddTransient<IKeyStore<RsaEncryptorDescriptor>>(p => new KeyStore<RsaEncryptorDescriptor>(p.CreateApiHttpClient(p.GetRequiredService<IOptions<IdentityServerOptions>>().Value),
p.GetRequiredService<ILogger<KeyStore<RsaEncryptorDescriptor>>>()))
.AddTransient<IKeyStore<IAuthenticatedEncryptorDescriptor>>(p => new KeyStore<IAuthenticatedEncryptorDescriptor>(p.CreateApiHttpClient(p.GetRequiredService<IOptions<IdentityServerOptions>>().Value),
p.GetRequiredService<ILogger<KeyStore<IAuthenticatedEncryptorDescriptor>>>()))
.AddAdminApplication(new Settings())
.AddDatabaseDeveloperPageExceptionFilter()
.AddRazorPages(options => options.Conventions.AuthorizeAreaFolder("Identity", "/Account"));
}

Expand Down Expand Up @@ -230,6 +254,13 @@ public void Configure(IApplicationBuilder app)

app
.UseAuthorization()
.Use((context, next) =>
{
var settings = context.RequestServices.GetRequiredService<Settings>();
var request = context.Request;
settings.WelcomeContenUrl = $"{request.Scheme}://{request.Host}/api/welcomefragment";
return next();
})
.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
Expand All @@ -239,7 +270,7 @@ public void Configure(IApplicationBuilder app)
endpoints.MapHub<ProviderHub>("/providerhub");
}
endpoints.MapFallbackToFile("index.html");
endpoints.MapFallbackToPage("/_Host");
});

if (isProxy)
Expand Down Expand Up @@ -318,14 +349,10 @@ private void AddDefaultServices(IServiceCollection services)
}
}

private void AddProxyServices(IServiceCollection services)
private void AddProxyServices(IServiceCollection services, Action<IdentityServerOptions> configureOptions)
{
void configureOptions(IdentityServerOptions options)
=> Configuration.GetSection("PrivateServerAuthentication").Bind(options);

services.AddTransient<ISchemeChangeSubscriber, SchemeChangeSubscriber<Auth.SchemeDefinition>>()
.AddIdentityProviderStore()
.AddConfigurationHttpStores(configureOptions)
services.AddTransient<ISchemeChangeSubscriber, SchemeChangeSubscriber<Auth.SchemeDefinition>>()
.AddIdentityProviderStore()
.AddOperationalHttpStores()
.AddIdentity<ApplicationUser, IdentityRole>(
options => Configuration.GetSection(nameof(IdentityOptions)).Bind(options))
Expand Down
6 changes: 3 additions & 3 deletions src/Aguacongas.TheIdServer/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
"LegacyAudienceValidation": true
},
"PrivateServerAuthentication": {
"Authority": "https://localhost:7443",
"ApiUrl": "https://localhost:7443/api",
"Authority": "https://localhost:5443",
"ApiUrl": "https://localhost:5443/api",
"ClientId": "public-server",
"ClientSecret": "84137599-13d6-469c-9376-9e372dd2c1bd",
"Scope": "theidserveradminapi",
Expand Down Expand Up @@ -99,7 +99,7 @@
},
"Serilog": {
"LevelSwitches": {
"$controlSwitch": "Information"
"$controlSwitch": "Warning"
},
"MinimumLevel": {
"ControlledBy": "$controlSwitch"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
<Authorized>
@if (Clicked.HasDelegate)
{
<button id="@Id" class="btn @CssSubClass" type="submit" @onclick="OnClicked">
<button id="@Id" class="btn mr-1 @CssSubClass" type="submit" @onclick="OnClicked">
<span class="oi oi-data-transfer-download"></span>
@Localizer["Save"]
</button>
}
else
{
<button id="@Id" class="btn @CssSubClass" type="submit" disabled="@_disabled">
<button id="@Id" class="btn mr-1 @CssSubClass" type="submit" disabled="@_disabled">
<span class="oi oi-data-transfer-download"></span>
@Localizer["Save"]
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public partial class SelectableItem<TItem>: IDisposable
{
private bool _value;
private bool disposedValue;
private bool _hasBeenRendered;

private bool Value
{
Expand Down Expand Up @@ -41,6 +42,12 @@ protected override void OnInitialized()
base.OnInitialized();
}

protected override void OnAfterRender(bool firstRender)
{
_hasBeenRendered = true;
base.OnAfterRender(firstRender);
}

private Task GridState_OnSelectAllClicked(bool value)
{
Value = value;
Expand All @@ -54,7 +61,11 @@ protected virtual void Dispose(bool disposing)
if (disposing)
{
GridState.OnSelectAllClicked -= GridState_OnSelectAllClicked;
Selected.InvokeAsync(false);
if (_hasBeenRendered)
{
Selected.InvokeAsync(false);
}

}
disposedValue = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,25 +62,12 @@ public static void ConfigureServices(IServiceCollection services, IConfiguration
options.AddIdentityServerPolicies();
});


services
services.AddSingleton(new HttpClient { BaseAddress = new Uri(baseAddress) })
.AddIdentityServer4AdminHttpStores(p =>
{
return Task.FromResult(CreateApiHttpClient(p));
})
.AddSingleton(new HttpClient { BaseAddress = new Uri(baseAddress) })
.AddSingleton(p => settings)
.AddSingleton<Notifier>()
.AddSingleton<IAuthenticationSchemeOptionsSerializer, AuthenticationSchemeOptionsSerializer>()
.AddSingleton<ISharedStringLocalizerAsync>(p => new StringLocalizer(p.GetRequiredService<IHttpClientFactory>().CreateClient("localizer"),
p.GetRequiredService<ILogger<AdminStore<Entity.LocalizedResource>>>(),
p.GetRequiredService<ILogger<AdminStore<Entity.Culture>>>(),
p.GetRequiredService<ILogger<StringLocalizer>>()))
.AddTransient<IAdminStore<User>, UserAdminStore>()
.AddTransient<IAdminStore<Role>, RoleAdminStore>()
.AddTransient<IAdminStore<ExternalProvider>, ExternalProviderStore>()
.AddTransient(typeof(IStringLocalizerAsync<>), typeof(StringLocalizer<>))
.AddTransient<OneTimeTokenService>()
.AddAdminApplication(settings)
.AddHttpClient("oidc")
.ConfigureHttpClient(httpClient =>
{
Expand All @@ -89,11 +76,33 @@ public static void ConfigureServices(IServiceCollection services, IConfiguration
})
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

services.AddHttpClient("localizer").ConfigureHttpClient(httpClient =>
{
var apiUri = new Uri(settings.ApiBaseUrl);
httpClient.BaseAddress = apiUri;
});
services.AddTransient<IAdminStore<Entity.LocalizedResource>>(p =>
{
var factory = p.GetRequiredService<IHttpClientFactory>();
return new AdminStore<Entity.LocalizedResource>(Task.FromResult(factory.CreateClient("localizer")), p.GetRequiredService<ILogger<AdminStore<Entity.LocalizedResource>>>());
}).AddTransient<IAdminStore<Entity.Culture>>(p =>
{
var factory = p.GetRequiredService<IHttpClientFactory>();
return new AdminStore<Entity.Culture>(Task.FromResult(factory.CreateClient("localizer")), p.GetRequiredService<ILogger<AdminStore<Entity.Culture>>>());
}).AddHttpClient("localizer").ConfigureHttpClient(httpClient =>
{
var apiUri = new Uri(settings.ApiBaseUrl);
httpClient.BaseAddress = apiUri;
});
}

public static IServiceCollection AddAdminApplication(this IServiceCollection services, Settings settings)
{
return services
.AddScoped(p => settings)
.AddScoped<Notifier>()
.AddScoped<IAuthenticationSchemeOptionsSerializer, AuthenticationSchemeOptionsSerializer>()
.AddScoped<ISharedStringLocalizerAsync, StringLocalizer>()
.AddTransient<IAdminStore<User>, UserAdminStore>()
.AddTransient<IAdminStore<Role>, RoleAdminStore>()
.AddTransient<IAdminStore<ExternalProvider>, ExternalProviderStore>()
.AddTransient(typeof(IStringLocalizerAsync<>), typeof(StringLocalizer<>))
.AddTransient<OneTimeTokenService>();
}

private static HttpClient CreateApiHttpClient(IServiceProvider p)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class Settings

public string AdministratorEmail { get; set; }
public string WelcomeContenUrl { get; set; }
public bool Prerendered { get; set; }
}

public class LoggingOptions
Expand Down
Loading

0 comments on commit ccf5040

Please sign in to comment.