Fork me on GitHub

一个HttpClient使用Windows认证请求WCF服务的例子

有个项目需要调用第三方SDK,而SDK获取服务器的已安装的特殊打印机列表返回给调用方。

但我不想依赖这个SDK,因为这个SDK是使用.NET Framework编写的,而我的项目是使用.NET Core编写的,并且想要部署在Docker容器内运行。

于是反编译了SDK,查看源代码,看到该SDK调用了一个URL获取结果。

而这个URL是本地URL,http://localhost开头的,此时我才知道这个SDK所对应的软件在服务器提供了一个本地的Web服务。

于是我在项目里移除这个SDK,直接调用URL。

但获取结果失败了,提示“响应状态代码不指示成功: 401 (Unauthorized)。”。而直接浏览器访问这个URL却成功返回结果。

 

刚开始一脸懵逼,不知道原来是没有认证的原因在作梗...

很习惯性的就祭出Fiddler监听这个URL,在浏览器里直接访问这个URL,在Fiddler却看到这个URL被请求了3次。

当时没有在意,直接拿到Request Header,塞到HttpClient的Header里,再次请求,还是报错。

重新粗略地看Fiddler,这时才留意到重复请求3次的问题。

我以为是请求内重定向,设置AllowAutoRedirect为true,再次请求,又报错。

又重新仔细地逐条看Fiddler,第二条在Request Header出现了Authorization: Negotiate xxxxxxxxx。

 

这才知道用了Authorization认证,于是我根据URL端口查到Windows的端口占用列表,顺便找到了该端口占用所对应的PID。

找到PID就找到了进程,从而找到进程所在的文件夹目录,查看它的config配置文件,从配置描述来看,这个Web服务更准确来讲是一个WCF服务。

它使用了security节点:

<security mode="TransportCredentialOnly">
  <transport clientCredentialType="Windows"></transport>
</security>

我设置UseDefaultCredentials为true,再次请求,成功获取结果。

这是HttpClient请求本地WCF服务 最终代码:

private static async void Test()
{
    Random rand = new Random();
    var r = rand.Next(10000, 99999);
    string url = "http://localhost:8080/WebPrintService/GetClientPrinters?rand=" + r;

    var handler = new HttpClientHandler();
    //handler.AllowAutoRedirect = true;
    //handler.UseDefaultCredentials = true;
    //handler.PreAuthenticate = true;

    HttpClient httpClient = new HttpClient(handler);
    
    //HttpRequestMessage requestMessage = new HttpRequestMessage();
    //requestMessage.RequestUri = new Uri(url);
    //requestMessage.Method = HttpMethod.Get;
    
    //requestMessage.Headers.CacheControl.MaxAge = TimeSpan.Zero;
    //requestMessage.Headers.Authorization=new AuthenticationHeaderValue();
    
    //requestMessage.Headers.Accept.Clear();
    //requestMessage.Headers.Accept.ParseAdd("application/json, text/javascript, */*; q=0.01");
    
    //requestMessage.Headers.AcceptEncoding.Clear();
    //requestMessage.Headers.AcceptEncoding.ParseAdd("gzip, deflate");
    
    //requestMessage.Headers.AcceptLanguage.Clear();
    //requestMessage.Headers.AcceptLanguage.ParseAdd("zh-CN");
    
    //requestMessage.Headers.UserAgent.Clear();
    //requestMessage.Headers.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko");

    //requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest");
    
    //var responseMessage = await httpClient.SendAsync(requestMessage);
    //var result = await responseMessage.Content.ReadAsStringAsync();
    
    var result = await httpClient.GetStringAsync(url);
    JsonConvert.DeserializeObject<PrinterInfo>(jsonString);
    
    //第二种写法,.NET Framework自带,无须为了HttpClient使用NuGet引入Microsoft.Net.Http包
    //WebRequest request = WebRequest.Create(url);
    //request.Method = "GET";
    //request.UseDefaultCredentials = true;
    //WebResponse response = request.GetResponse();
    //var stream = response.GetResponseStream();
    //using (var streamReader = new StreamReader(stream))
    //{
    //    using (var textReader = new JsonTextReader(streamReader))
    //    {
    //        var serializer = new JsonSerializer();
    //        var result = serializer.Deserialize<List<PrinterInfo>>(textReader);
    //    }
    //}
}
posted @ 2017-07-26 13:53  VAllen  阅读(1338)  评论(0编辑  收藏  举报