using BoardApp.Session;
|
|
namespace BoardApp.Middleware;
|
|
public sealed class BoardRequireAuthMiddleware
|
{
|
private readonly RequestDelegate _next;
|
|
public BoardRequireAuthMiddleware(RequestDelegate next)
|
{
|
_next = next;
|
}
|
|
private static bool IsAnonymousAllowed(PathString path)
|
{
|
// PathBase (/board) is stripped by UsePathBase, so we only see inner path here.
|
var p = path.Value ?? "";
|
|
if (p.StartsWith("/static/", StringComparison.OrdinalIgnoreCase)) return true;
|
if (string.Equals(p, "/login", StringComparison.OrdinalIgnoreCase)) return true;
|
if (string.Equals(p, "/api/login", StringComparison.OrdinalIgnoreCase)) return true;
|
if (string.Equals(p, "/api/winauth/login", StringComparison.OrdinalIgnoreCase)) return true;
|
if (string.Equals(p, "/api/winauth/negotiate", StringComparison.OrdinalIgnoreCase)) return true;
|
if (string.Equals(p, "/check/", StringComparison.OrdinalIgnoreCase)) return true;
|
|
// Everything else under /board requires login (same as Node version router-level auth).
|
return false;
|
}
|
|
public async Task Invoke(HttpContext ctx)
|
{
|
if (IsAnonymousAllowed(ctx.Request.Path))
|
{
|
await _next(ctx);
|
return;
|
}
|
|
var user = ctx.Session.GetJson<SessionUser>("user");
|
if (user is not null && !string.IsNullOrWhiteSpace(user.Username))
|
{
|
await _next(ctx);
|
return;
|
}
|
|
var nextUrl = (ctx.Request.PathBase + ctx.Request.Path + ctx.Request.QueryString).ToString();
|
var acceptsHtml = ctx.Request.Headers.Accept.Any(a => a?.Contains("text/html", StringComparison.OrdinalIgnoreCase) == true);
|
if (acceptsHtml)
|
{
|
var redirect = (ctx.Request.PathBase + "/login?next=" + Uri.EscapeDataString(nextUrl)).ToString();
|
ctx.Response.Redirect(redirect);
|
return;
|
}
|
|
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
await ctx.Response.WriteAsJsonAsync(new { error = "Unauthorized" });
|
}
|
}
|
|