C#HttpListener多种身份验证方案和Chrome

时间:2018-02-28 09:01:47

标签: c# google-chrome http httplistener www-authenticate

好的,这是一个很长的问题,但我认为值得这样做。我们有什么:

  1. 一个虚拟C#控制台应用程序示例,它启动自托管的ASP.Net WebAPI服务( Microsoft.AspNet.WebApi.OwinSelfHost NuGet包):

    class Program
    {
        static void Main(string[] args)
        {
            var url = "http://localhost:8080/";
    
            Console.WriteLine($"Starting on {url}");
            using (WebApp.Start<Startup>(url))
            {
                Console.WriteLine("Success! Press any key to stop...");
                Console.ReadKey();
            }
        }
    }
    
  2. OWIN启动课程:

    class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // enable Windows AND Anonymous authentication
            var listener = app.Properties["System.Net.HttpListener"] as HttpListener;
            listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous |
                AuthenticationSchemes.IntegratedWindowsAuthentication;
    
            // configure WebAPI
            var config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();
    
            app.UseWebApi(config);
        }
    }
    
  3. 使用两种公共方法的示例WebAPI控制器:

    [RoutePrefix("sample"), Authorize]
    public class SampleController : ApiController
    {
        [Route("public"), AllowAnonymous]
        public object GetPublicSample()
        {
            var message = $"Hi there, mr. {User?.Identity?.Name ?? "ANONYMOUS"}";
            return new { sample = 0, message };
        }
    
        [Route("protected")]
        public object GetProtectedSample()
        {
            var message = $"Hi there, mr. {User?.Identity?.Name ?? "ANONYMOUS"}";
            return new { sample = 42, message };
        }
    }
    
  4. 现在,当我们运行项目并将chrome指向http://localhost:8080/sample/public时,会调用此请求:

    GET /sample/public HTTP/1.1
    Host: localhost:8080
    
    HTTP/1.1 200 OK
    Content-Length: 50
    Content-Type: application/json; charset=utf-8
    Server: Microsoft-HTTPAPI/2.0
    Date: Wed, 28 Feb 2018 08:05:56 GMT
    
    {"sample":0,"message":"Hi there, mr. ANONYMOUS"}
    

    但是当我们去http://localhost:8080/sample/protected时,我们有了这个:

    GET /sample/protected HTTP/1.1
    Host: localhost:8080
    
    HTTP/1.1 401 Unauthorized
    date: Wed, 28 Feb 2018 08:19:01 GMT
    www-authenticate: Negotiate,NTLM
    server: Microsoft-HTTPAPI/2.0
    content-length: 61
    content-type: application/json; charset=utf-8
    
    {"Message":"Authorization has been denied for this request."}
    

    这几乎是&#34;正如所料&#34;除了1件事。我希望当我的浏览器收到带有www-authenticate标头的401 HTTP响应时,他将尝试使用指定的身份验证重复相同的请求(如果请求中没有任何其他Authorization标头)。但出于某种原因,他没有:(

    为了让事情变得更有趣,我们可以看到 AuthenticationSchemes.IntegratedWindowsAuthentication 实际上是 AuthenticationSchemes.Negotiate | AuthenticationSchemes.Ntlm ,当我删除其中一个时,事情开始起作用如预期!例如:在我们的启动课程中将 IntegratedWindowsAuthentication 替换为 Negotiate ,然后将您的brouser转到http://localhost:8080/sample/protected

    GET /sample/protected HTTP/1.1
    Host: localhost:8080
    
    HTTP/1.1 200 OK
    date: Wed, 28 Feb 2018 08:29:55 GMT
    www-authenticate: tOkeN1231351234153=
    server: Microsoft-HTTPAPI/2.0
    content-length: 59
    content-type: application/json; charset=utf-8
    
    {"sample":42,"message":"Hi there, mr. DOMAIN\\username"}
    

    通常,我们的服务器首先响应401 HTTP状态并设置标题 www-authenticate: Negotiate ,然后使用其他授权标头重复浏览请求。如果我们将 IntegratedWindowsAuthentication 替换为 Ntlm ,也是一样。

    又一个让事情更清晰的例子。如果我们移除 AuthenticationSchemes.Anonymous 并仅保留 AuthenticationSchemes.IntegratedWindowsAuthentication ,我们会注意到结果中的两件事:

    1. /sample/public端点不再可用于匿名请求(正如预期的那样)
    2. /sample/protected端点现在正常工作(!)
    3. 如果我们先查看401服务器响应,我们会注意到有两个www-authenticate标头而不是一个(如前所述):

      GET /sample/protected HTTP/1.1
      Host: localhost:8080
      
      HTTP/1.1 401 Unauthorized
      Content-Length: 0
      Server: Microsoft-HTTPAPI/2.0
      WWW-Authenticate: Negotiate
      WWW-Authenticate: NTLM
      Date: Wed, 28 Feb 2018 08:44:04 GMT
      

      所以,我的问题是:它是&#34;好的&#34;将多个身份验证方案放在单个 www-authenticate 标头中?如果&#34;是的,它没关系&#34;,为什么我的chrome没有解决这种情况?如果&#34;不!一切都错了!&#34;,为什么HttpListener这样做,我怎么能绕过这个?请等一下!

1 个答案:

答案 0 :(得分:0)

这已经有一段时间了,但是我想提供我的.02。 AuthenticationSchemes.IntegratedWindowsAuthentication有点奇怪。 IWA与设置“协商”和“ NTLM”相同。另一方面,如果Kerberos失败,协商将退回到NTLM。 ASP.NET Core枚举中没有IWA:See ASP.NET Core AuthenticationSchemes Enum

我使用:

listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous | AuthenticationSchemes.Negotiate;