Skip to content

Commit e79c24f

Browse files
committed
Fix: Redirect 401 to login page (#21)
1 parent a1ce1db commit e79c24f

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

src/NzbDrone.Host/Startup.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ public void Configure(IApplicationBuilder app,
304304
});
305305

306306
app.UseAuthentication();
307+
app.UseBrowserRedirect(); // workaround to convert 401 to 302 for browser requests
307308
app.UseAuthorization();
308309
app.UseResponseCompression();
309310
app.Properties["host.AppName"] = BuildInfo.AppName;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Microsoft.AspNetCore.Builder;
4+
using Microsoft.AspNetCore.Http;
5+
using Microsoft.Extensions.Logging;
6+
7+
namespace Whisparr.Http.Middleware
8+
{
9+
public class BrowserRedirectMiddleware
10+
{
11+
private readonly RequestDelegate _next;
12+
private readonly ILogger<BrowserRedirectMiddleware> _logger;
13+
14+
public BrowserRedirectMiddleware(RequestDelegate next, ILogger<BrowserRedirectMiddleware> logger)
15+
{
16+
_next = next;
17+
_logger = logger;
18+
}
19+
20+
public async Task InvokeAsync(HttpContext context)
21+
{
22+
// Only act on browser requests (Accept: text/html), not /api or /signalr
23+
var path = context.Request.Path.Value ?? string.Empty;
24+
if (path.StartsWith("/api", StringComparison.OrdinalIgnoreCase) ||
25+
path.StartsWith("/signalr", StringComparison.OrdinalIgnoreCase))
26+
{
27+
await _next(context);
28+
return;
29+
}
30+
31+
// Buffer the response
32+
var originalBody = context.Response.Body;
33+
using (var memStream = new System.IO.MemoryStream())
34+
{
35+
context.Response.Body = memStream;
36+
await _next(context);
37+
memStream.Position = 0;
38+
39+
// Check if we should redirect
40+
var isBrowser = context.Request.Headers["Accept"].ToString().Contains("text/html", StringComparison.OrdinalIgnoreCase);
41+
var is401 = context.Response.StatusCode == StatusCodes.Status401Unauthorized;
42+
var hasLocation = context.Response.Headers.ContainsKey("Location");
43+
44+
if (isBrowser && is401 && hasLocation)
45+
{
46+
var location = context.Response.Headers["Location"].ToString();
47+
_logger.LogDebug("BrowserRedirectMiddleware: Converting 401+Location to 302 for {Path} -> {Location}", path, location);
48+
context.Response.Clear();
49+
context.Response.StatusCode = StatusCodes.Status302Found;
50+
context.Response.Headers["Location"] = location;
51+
}
52+
else
53+
{
54+
memStream.Position = 0;
55+
await memStream.CopyToAsync(originalBody);
56+
}
57+
58+
context.Response.Body = originalBody;
59+
}
60+
}
61+
}
62+
63+
public static class BrowserRedirectMiddlewareExtensions
64+
{
65+
public static Microsoft.AspNetCore.Builder.IApplicationBuilder UseBrowserRedirect(this Microsoft.AspNetCore.Builder.IApplicationBuilder builder)
66+
{
67+
return builder.UseMiddleware<BrowserRedirectMiddleware>();
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)