a simpler UI
This commit is contained in:
parent
84160f0759
commit
2263311e1b
4 changed files with 122 additions and 5 deletions
|
|
@ -59,11 +59,20 @@ public partial class Settings : ObservableObject
|
|||
/// (no client secret). The browser implementation should be supplied
|
||||
/// per-platform by the caller.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <see cref="AuthenticationSettings.Authority"/> is normalised by
|
||||
/// trimming any trailing slash before being handed to <c>OidcClient</c>.
|
||||
/// <c>OidcClient</c> derives the discovery URL from
|
||||
/// <c>Authority + "/.well-known/openid-configuration"</c>; leaving a
|
||||
/// trailing slash in place would produce a double-slash URL that some
|
||||
/// servers reject with 404.
|
||||
/// </remarks>
|
||||
internal OidcClientOptions GetOidcClientOptions(IdentityModel.OidcClient.Browser.IBrowser? browser = null)
|
||||
{
|
||||
var authority = Authentication.Authority?.TrimEnd('/') ?? string.Empty;
|
||||
var options = new OidcClientOptions
|
||||
{
|
||||
Authority = Authentication.Authority,
|
||||
Authority = authority,
|
||||
ClientId = Authentication.ClientId,
|
||||
RedirectUri = RedirectUri,
|
||||
Scope = string.Join(' ', this.Scopes),
|
||||
|
|
|
|||
|
|
@ -31,6 +31,23 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
public bool HasRegisterUrl => !string.IsNullOrEmpty(RegisterUrl);
|
||||
public bool HasForgotPasswordUrl => !string.IsNullOrEmpty(ForgotPasswordUrl);
|
||||
|
||||
/// <summary>
|
||||
/// Canonical <see cref="Settings.Authentication"/> authority with any trailing
|
||||
/// slash removed. Used as the base for both the OIDC discovery URL and the
|
||||
/// human-facing Account URLs (Register / Forgot password). Empty when the
|
||||
/// authority is not configured.
|
||||
/// </summary>
|
||||
public string ExternalUrl => BuildExternalUrl(string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// OIDC discovery URL the client actually calls during login:
|
||||
/// <c>ExternalUrl + "/.well-known/openid-configuration"</c>. Surfaced in
|
||||
/// <see cref="StatusMessage"/> on failure so the operator can copy it
|
||||
/// verbatim and verify reachability from a browser.
|
||||
/// </summary>
|
||||
public string DiscoveryUrl =>
|
||||
string.IsNullOrEmpty(ExternalUrl) ? string.Empty : ExternalUrl + "/.well-known/openid-configuration";
|
||||
|
||||
/// <summary>
|
||||
/// True when the settings file is missing or <c>Authentication.Authority</c>
|
||||
/// is empty. The LoginPage surfaces a banner in that case and disables
|
||||
|
|
@ -112,12 +129,21 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
? Platform.DefaultRedirectUri
|
||||
: Settings.RedirectUri;
|
||||
|
||||
// Surface the discovery URL the client is about to call, so a
|
||||
// failure (DNS, TLS, 404) can be diagnosed by pasting the URL
|
||||
// straight into a browser. OidcClient computes the discovery
|
||||
// URL as `Authority + /.well-known/openid-configuration`; we
|
||||
// normalise the trailing slash here so the printed URL is
|
||||
// exactly what IdentityModel will fetch.
|
||||
if (!string.IsNullOrEmpty(DiscoveryUrl))
|
||||
StatusMessage = $"Discovering {DiscoveryUrl}";
|
||||
|
||||
var browser = BrowserFactoryOverride is not null
|
||||
? BrowserFactoryOverride.Invoke()
|
||||
: Platform.CreateBrowser?.Invoke();
|
||||
if (browser is null)
|
||||
{
|
||||
StatusMessage = "No browser is available on this platform.";
|
||||
StatusMessage = $"No browser is available on this platform. (discovery: {DiscoveryUrl})";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +152,7 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
|
||||
if (loginResult.IsError)
|
||||
{
|
||||
StatusMessage = loginResult.Error;
|
||||
StatusMessage = $"{loginResult.Error} (discovery: {DiscoveryUrl})";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +170,8 @@ public partial class LoginPageViewModel : ViewModelBase
|
|||
catch (Exception ex)
|
||||
{
|
||||
this.IsBusy = false;
|
||||
StatusMessage = "Error: "+ex.Message;
|
||||
var suffix = !string.IsNullOrEmpty(DiscoveryUrl) ? $" (discovery: {DiscoveryUrl})" : string.Empty;
|
||||
StatusMessage = $"Error: {ex.Message}{suffix}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,12 @@
|
|||
IsEnabled="{Binding HasForgotPasswordUrl}"
|
||||
Click="OnForgotPasswordClick"/>
|
||||
|
||||
<TextBlock Name="StatusText" Text="{Binding StatusMessage}" TextWrapping="Wrap" />
|
||||
<TextBox Name="StatusText"
|
||||
Text="{Binding StatusMessage}"
|
||||
TextWrapping="Wrap"
|
||||
IsReadOnly="True"
|
||||
BorderThickness="0"
|
||||
Background="Transparent"/>
|
||||
<ProgressBar IsIndeterminate="{Binding IsBusy}" />
|
||||
|
||||
</StackPanel>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue