c23039efa1
The app stuck on "Chargement…" after sign-in because the interactive Blazor circuit came up anonymous: no auth cookie reached this origin. Root cause was the deployment (plain HTTP on an IP, http://host:8080), which Microsoft OIDC cannot serve — Entra forbids http redirect URIs for non-localhost hosts, so the sign-in cookie never lands on the origin. Changes: - ForwardedHeaders (X-Forwarded-Proto/For) so that behind a TLS proxy the app sees the real https scheme, builds a matching OIDC redirect_uri, and sets the auth cookie Secure. Proxy IP unknown in-container → known proxy/network restrictions cleared. - First-run bootstrap: seed a local admin (Bootstrap__AdminEmail / Bootstrap__AdminPassword) when that email has no account, so HTTP/LAN deployments that can't use OIDC can sign in via the local form. Idempotent. - OIDC SaveTokens=false: the cookie-stored access/id/refresh tokens were never read (SharePoint/Graph auth uses the separate connect-flow + cert paths). Dropping them keeps the auth cookie small/unchunked. - AppInitializer now logs which branch leaves UserContext unseeded (unauthenticated principal / missing claim / no user row) instead of failing silently — this is what surfaced the anonymous-circuit cause. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
43 lines
1.7 KiB
Plaintext
43 lines
1.7 KiB
Plaintext
@inject AuthenticationStateProvider AuthProvider
|
|
@inject IUserService UserService
|
|
@inject IUserContextAccessor UserContext
|
|
@inject ILogger<AppInitializer> Logger
|
|
@using Microsoft.AspNetCore.Components.Authorization
|
|
@using SharepointToolbox.Web.Services.Auth
|
|
@using SharepointToolbox.Web.Services.Session
|
|
|
|
@* Invisible component. Run once per circuit to seed IUserContextAccessor. *@
|
|
|
|
@code {
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
var state = await AuthProvider.GetAuthenticationStateAsync();
|
|
var principal = state.User;
|
|
|
|
if (principal.Identity?.IsAuthenticated != true)
|
|
{
|
|
Logger.LogWarning("AppInitializer: circuit principal NOT authenticated; UserContext left unseeded → page stays on loading.");
|
|
return;
|
|
}
|
|
|
|
var email = principal.FindFirst("preferred_username")?.Value
|
|
?? principal.FindFirst(System.Security.Claims.ClaimTypes.Email)?.Value;
|
|
if (string.IsNullOrEmpty(email))
|
|
{
|
|
var claims = string.Join(", ", principal.Claims.Select(c => $"{c.Type}={c.Value}"));
|
|
Logger.LogWarning("AppInitializer: authenticated but no preferred_username/email claim. Claims present: [{Claims}]", claims);
|
|
return;
|
|
}
|
|
|
|
var user = await UserService.GetByEmailAsync(email);
|
|
if (user is null)
|
|
{
|
|
Logger.LogWarning("AppInitializer: no user row for email '{Email}' — provisioning did not persist a matching record.", email);
|
|
return;
|
|
}
|
|
|
|
Logger.LogInformation("AppInitializer: seeded UserContext for '{Email}' (role {Role}).", user.Email, user.Role);
|
|
UserContext.Initialize(user);
|
|
}
|
|
}
|