fix(security,adminui): logout redirects to /login + restyle login card
Some checks failed
v2-ci / build (push) Failing after 41s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped

Two small UX fixes:

- AuthEndpoints.LogoutAsync now redirects browser callers to /login after
  SignOutAsync instead of returning 204 NoContent. 204 was correct for the
  REST contract but left browsers stuck on the page they came from (the
  cookie was cleared but no navigation happened, so "Sign out" appeared
  to do nothing). API callers can still opt into the status-only behavior
  by sending `Accept: application/json`.

- Login.razor drops the .panel-head top strip; the sign-in card now reads
  as a self-contained form with an inline title "MxAccess Gateway Admin —
  sign in". Added a .login-title CSS class to site.css that matches the
  panel-head's typographic weight without the bar.
This commit is contained in:
Joseph Doherty
2026-05-26 14:47:53 -04:00
parent ed1c17bc7b
commit c064ec16cf
3 changed files with 20 additions and 3 deletions

View File

@@ -10,8 +10,8 @@
<div class="login-wrap rise" style="animation-delay:.02s"> <div class="login-wrap rise" style="animation-delay:.02s">
<section class="panel"> <section class="panel">
<div class="panel-head">OtOpcUa Admin &mdash; sign in</div> <div style="padding:1.4rem 1.1rem 1.25rem">
<div style="padding:1.1rem 1.1rem 1.25rem"> <h1 class="login-title">MxAccess Gateway Admin &mdash; sign in</h1>
<form method="post" action="/auth/login" data-enhance="false"> <form method="post" action="/auth/login" data-enhance="false">
@if (ReturnUrl is not null) @if (ReturnUrl is not null)
{ {

View File

@@ -49,6 +49,16 @@
} }
} }
/* Login card title. Replaces the panel-head top strip on the login page so the
card reads as a self-contained sign-in form, not a tabbed panel. */
.login-title {
margin: 0 0 1.1rem 0;
font-size: 1.05rem;
font-weight: 600;
letter-spacing: 0.01em;
color: var(--ink);
}
/* Brand block pinned at the top of the side rail. Mirrors ScadaLink's /* Brand block pinned at the top of the side rail. Mirrors ScadaLink's
.sidebar .brand styling — used now that the top app-bar was dropped. */ .sidebar .brand styling — used now that the top app-bar was dropped. */
.side-rail .brand { .side-rail .brand {

View File

@@ -115,6 +115,13 @@ public static class AuthEndpoints
private static async Task<IResult> LogoutAsync(HttpContext http) private static async Task<IResult> LogoutAsync(HttpContext http)
{ {
await http.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await http.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Results.NoContent();
// Browser form POST → redirect to /login so the user lands somewhere visible.
// API callers that prefer the status-only contract should hit the endpoint with
// Accept: application/json and we'll hand them a 204 instead.
var wantsJson = http.Request.Headers.Accept.Any(v =>
v?.Contains("application/json", StringComparison.OrdinalIgnoreCase) == true);
if (wantsJson) return Results.NoContent();
return Results.Redirect("/login");
} }
} }