81 lines
3.4 KiB
C#
81 lines
3.4 KiB
C#
using System.Net;
|
|
using Microsoft.AspNetCore.Antiforgery;
|
|
|
|
namespace SharepointToolbox.Web.Infrastructure.Auth;
|
|
|
|
/// <summary>Renders the combined login page (Microsoft / Entra button + local credential form)
|
|
/// as a self-contained static HTML response. Lives outside the interactive Blazor circuit so
|
|
/// the POST handler can issue the auth cookie directly on the HTTP request.</summary>
|
|
public static class LoginPageRenderer
|
|
{
|
|
public static string Build(
|
|
HttpContext ctx,
|
|
IAntiforgery antiforgery,
|
|
string? returnUrl,
|
|
bool showError,
|
|
bool showEntra = true,
|
|
bool showDevButton = false)
|
|
{
|
|
var tokens = antiforgery.GetAndStoreTokens(ctx);
|
|
var ru = WebUtility.HtmlEncode(returnUrl ?? "/");
|
|
var afField = WebUtility.HtmlEncode(tokens.FormFieldName);
|
|
var afToken = WebUtility.HtmlEncode(tokens.RequestToken);
|
|
|
|
var error = showError
|
|
? "<div class=\"alert alert-error\">Invalid email or password.</div>"
|
|
: string.Empty;
|
|
|
|
var entraButton = showEntra
|
|
? $"<a class=\"btn btn-secondary btn-block\" href=\"/account/login/entra?returnUrl={ru}\">Sign in with Microsoft</a><div class=\"login-divider\">or</div>"
|
|
: string.Empty;
|
|
|
|
var devButton = showDevButton
|
|
? $"<div class=\"login-divider\">dev</div><a class=\"btn btn-secondary btn-block\" href=\"/account/login/dev?returnUrl={ru}\">Quick sign in as Dev Admin</a>"
|
|
: string.Empty;
|
|
|
|
return $$"""
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Sign in — SharePoint Toolbox</title>
|
|
<link rel="stylesheet" href="/app.css" />
|
|
<style>
|
|
body { display:flex; align-items:center; justify-content:center; min-height:100vh; margin:0; background:var(--bg); }
|
|
.login-card { width:360px; max-width:92vw; }
|
|
.login-card h1 { font-size:20px; margin:0 0 4px; color:var(--text); }
|
|
.login-card .sub { font-size:13px; color:var(--text-muted); margin:0 0 18px; }
|
|
.login-divider { display:flex; align-items:center; gap:10px; color:var(--text-muted); font-size:12px; margin:18px 0; }
|
|
.login-divider::before, .login-divider::after { content:""; flex:1; height:1px; background:var(--border); }
|
|
.field { margin-bottom:12px; }
|
|
.btn-block { width:100%; justify-content:center; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card login-card">
|
|
<h1>SharePoint Toolbox</h1>
|
|
<p class="sub">Sign in to continue</p>
|
|
{{error}}
|
|
{{entraButton}}
|
|
<form method="post" action="/account/local-login">
|
|
<input type="hidden" name="returnUrl" value="{{ru}}" />
|
|
<input type="hidden" name="{{afField}}" value="{{afToken}}" />
|
|
<div class="field">
|
|
<label class="form-label" for="email">Email</label>
|
|
<input class="form-input" id="email" name="email" type="email" autocomplete="username" required autofocus />
|
|
</div>
|
|
<div class="field">
|
|
<label class="form-label" for="password">Password</label>
|
|
<input class="form-input" id="password" name="password" type="password" autocomplete="current-password" required />
|
|
</div>
|
|
<button class="btn btn-primary btn-block" type="submit">Sign in</button>
|
|
</form>
|
|
{{devButton}}
|
|
</div>
|
|
</body>
|
|
</html>
|
|
""";
|
|
}
|
|
}
|