基本身份验证重定向到登录页面而不是返回身份验证质询

Basic Authentication redirects to login page instead of returning an auth challenge

除了标准的开箱即用 cookies/forms 身份验证之外,我还需要支持 SignalR 的基于 HTTPS 的基本身份验证。 SignalR 在混合 MVC/WebApi 站点的上下文中运行。

将各个部分放在一起如何实现之后,我在服务器上为此使用了 ThinkTecture.IdentityModel.Owin.BasicAuthentication 库,如下所示:

app.Map("/basicauth", map =>
{
    map.UseBasicAuthentication("realm", ValidateUser);
    map.MapSignalR<AuthenticatedEchoConnection>("/echo");
    map.MapSignalR();
});

但我总是收到重定向到 MVC 站点登录页面的 HTTP 302 响应,而不是返回质询。为了更好地调试它,我快速推出了自己的简单 OWIN 中间件以进行基本身份验证,并得到了相同的结果。使用像这样的简单映射进一步测试:

app.Map("/test", map =>
    {
        map.Use((context, next) =>
            {
                // context.Response.StatusCode = 401;
                context.Response.Write("Hello World!");
                return Task.FromResult(0);
            });

揭示了一个简单的 "Hello World" 响应是正常返回的。但是当我注释掉将响应代码设置为 401 的行时,我再次重定向到登录页面。我不明白这种行为……为什么我的 MVC 站点会涉及到这里而不返回 401 响应?我该如何防止这种情况?

对于 OWIN,除了上面的特殊 /basicauth 映射之外,我在启动方法中只定义了顶级 SignalR 映射,它应该继续为所有 cookie 身份验证的调用工作:

app.MapSignalR();

我没有为 OWIN 配置任何其他内容。

谁能帮我解决这个问题?

好的,我找到了解决此问题的方法。第一部分是从第一个示例中删除 map.MapSignalR<AuthenticatedEchoConnection>("/echo"); - 这是没有必要的,并且出于某种原因我没有发现它阻止了 SignalR 正常工作。

第二部分,以及实际问题的解决方法,是在客户端中,我还随第一个请求发送凭据,而不是等待质询。因此,401 永远不会发生,因此不会重定向到登录页面。这对我来说已经足够了。

所以解决方法是,在客户端中,不要像这样使用 NetworkCredential:

connection.Credentials = new NetworkCredential(username, password);

相反,您自己添加授权 header,以便它已包含在第一个请求中:

string creds = string.format("{0}:{1}", username, password);
string encodedCreds = Convert.ToBase64String(Encoding.Utf8.GetBytes(creds));
connection.Headers.Add("Authorization", "Basic " + encodedCreds);

此外,我发现对于 OWIN,这个问题似乎更普遍,不仅与 SignalR 甚至 Basic Auth 一起使用时相关:

http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/

因此,通过对基本身份验证模块进行一些修改,应该也可以防止这种重定向。我可能会调查一下,完成后会更新这个 post。