Admin back office
An internal tool for staff: lists, edit forms, a dashboard, roles. Everything is behind sign-in, and mistakes are expensive, so authorization and auditing matter more than caching.
Roles and permissions
Put groups (roles) and permissions on your users (WebUser.Groups, WebUser.Permissions) or resolve
permissions from your own tables with IWebPermissionResolver (web.UsePermissionResolver<T>();
resolved only when a rule needs them).
web.AddAuthorizationPolicy("support", p => p.RequireAnyGroup("support", "admin"));
var admin = b.MapGroup("/admin").RequireGroups("staff")
.WithLoginPath("/admin/login").WithAccessDeniedPath("/admin/denied");
admin.MapPage("/customers", ListCustomersAsync).RequirePolicy("support");
admin.MapPage("/customers/{id}/refund", RefundAsync, "POST").RequirePermissions("billing.refund");
Permission wildcards (billing.*) are supported. Handlers still check resource access themselves (a
support agent of region A editing a customer of region B).
Sign-in hardening
- Require two-factor for staff and recent proof for dangerous actions:
admin.RequireRecentSignInAnyOf(TimeSpan.FromHours(8), ["otp"], ["passkey"])on the whole area, and.RequireRecentSignInAnyOf(TimeSpan.FromMinutes(10), ["pwd", "otp"], ["passkey"])on refunds or user management. Staff without 2FA are sent to the admin login page; a "confirm it's you" form callsrequest.Auth.ReauthenticateAsync(password, code). - Passkeys are the easiest strong option for staff: a passkey sign-in counts as multi-factor, a passkey
can stand in for the TOTP code, and
ReauthenticateWithPasskeyAsyncanswers the "confirm it's you" step. A passkey recordspasskey(nototp), so accept both ways with alternatives:admin.RequireRecentSignInAnyOf(TimeSpan.FromHours(8), ["pwd", "otp"], ["passkey"]). See Passkeys. - External sign-in (company SSO) goes through
SignInExternalAsync, so the same two-factor rules apply. auth.lockout, the per-login throttle and the per-IP cap are on by default.- Shorter sessions:
security.session.idleTimeoutMinutes: 30,absoluteTimeoutHours: 12. - Optionally limit by network:
security.ipRules.allowwith the office/VPN ranges (applies to the whole site), or a custom requirement for just/admin. request.Auth.SignOutAsync(everywhere: true)for "sign out all devices",ListSessionsAsync/RevokeSessionAsyncfor a device list,Session.MaxPerUserto cap concurrent sessions andNotifyNewDevicefor sign-in alerts; disabling a user ends their sessions at the next stamp check.
Forms
Edit forms use request.Forms.Prefill(model) and BindAsync<T>(); IWebFormValidator<T> covers
uniqueness checks. Options providers with a Policy keep lookup endpoints (customers, products) for
staff only. Wizards fit multi-step operations (onboarding a customer) without server-side state.
Dashboard
A staff dashboard with widgets (open tickets, sales today, system health) on
WebDashboardService.RenderAsync. Per-user layouts by default; return a shared owner key from your
IWebDashboardOwnerResolver for a team wall. Widgets with o.Access only appear for staff who may
see them.
Audit
web.UseAuditSink<DatabaseAuditSink>();
"security": { "audit": { "enabled": true, "ipHashKey": "<secret>" } }
Sign-ins, failures, lockouts, 2FA changes, API key use and every rejected request reach your sink. Add your own domain events ("refund issued") to the same table from your handlers.
Explorer
Leave the explorer off in production, or enable it with explorer.inProduction for holders of
weblogic.explorer only. Its anonymous-route list is a quick review that nothing in /admin is open.