如何基于HttpClient和.net4使用Rest-client进行身份验证

50

我一直在使用HttpClient构建REST客户端,但我无法弄清楚如何向服务器进行身份验证,也找不到任何示例。最有可能我会使用基本身份验证,但确实任何示例都会受到赞赏。

在早期版本中(有在线示例),您可以这样做:

HttpClient client = new HttpClient("http://localhost:8080/ProductService/");
client.TransportSettings.Credentials =
    new System.Net.NetworkCredential("admin", "admin");

然而,在版本0.3.0中,TransportSettings属性已不再存在。

8个回答

111

所有这些都已经过时了。最终的方法如下:

var credentials = new NetworkCredential(userName, password);
var handler = new HttpClientHandler { Credentials = credentials };

using (var http = new HttpClient(handler))
{
    // ...
}

8
我正在使用VS2013和.NET 4.5。授权标头未设置。我只能通过属性直接设置标头。我可能还遗漏了什么? - Alex
9
尝试将 HttpClientHandler.PreAuthenticate 设为 true,详情请参阅 http://msdn.microsoft.com/en-us/library/system.net.http.httpclienthandler.preauthenticate.aspx。 - Duncan Smart
太棒了。@DuncanSmart 值得再加一个 +1。 - M.S.

17

HttpClient库没有被纳入.NET 4中。但是可以在这里找到它:http://nuget.org/List/Packages/HttpClient。不过,在这个版本的HttpClient中,身份验证是以不同的方式完成的。

var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization 
                   = new AuthenticationHeaderValue("basic","...");
或。
var webRequestHandler = new WebRequestHandler();
CredentialCache creds = new CredentialCache();
creds.Add(new Uri(serverAddress), "basic",
                        new NetworkCredential("user", "password"));
webRequestHandler.Credentials = creds;
var httpClient = new HttpClient(webRequestHandler);

请注意,这个库将在下周更新,并且会有一些小的破坏性改变!


抱歉让你感到困惑了。那是我得到的版本,来自NuGet。 - Tomas
1
我尝试过那个,但似乎无法使其工作。但据我所知,“...”应该是以uname:pwd为基础64编码的? - Tomas
嗯...我以为它能工作了,但是无法与基本身份验证和预先身份验证一起使用...感谢您的指导。 - Tomas
谢谢,这对我也很有用。唯一需要补充的是一些服务器对于其标头是大小写敏感的,并更喜欢使用“Basic”而不是“basic”。(我刚刚发现了这个) - Program.X

9
我尝试了Duncan的建议,但在我的情况下没有起作用。我怀疑这是因为我集成的服务器没有发送挑战或请求身份验证。它只是拒绝了我的请求,因为我没有提供Authorization头部。
所以我做了以下操作:
using (var client = new HttpClient())
{
    var encoding = new ASCIIEncoding();
    var authHeader = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(encoding.GetBytes(string.Format("{0}:{1}", "username", "password"))));
    client.DefaultRequestHeaders.Authorization = authHeader;
    // Now, the Authorization header will be sent along with every request, containing the username and password.
}

请注意,此示例仅适用于基本身份验证

3

从.NET 4.8开始,.NET Core 3.1和.NET Standard 2.0建议同时使用HttpClientCredentialCache。类似于这样:

const string basicAuthUser = @"myUser";
const string basicAuthPass = @"myPass";
const string host = @"https://my.host.com";
const string path = @"/api";

using (var httpClientHandler = new HttpClientHandler()) {
    httpClientHandler.PreAuthenticate = true;
    httpClientHandler.UseDefaultCredentials = true;

    var basicCredCache = new CredentialCache();
    var basicCredentials = new NetworkCredential(basicAuthUser, basicAuthPass);
    basicCredCache.Add(new Uri(new Uri(host), path), "Basic", basicCredentials);
    httpClientHandler.Credentials = basicCredCache;

    using (var client = new HttpClient(httpClientHandler)) {
        client.BaseAddress = new Uri(host);
        using (var request = new HttpRequestMessage(HttpMethod.Get /*HttpMethod.Post*/, path)) {
            //
            // Send request here
            //
        }
    }
}

注意:将HttpClient包装在using中可能会在高负载下导致Socket耗尽。 但是,保持HttpClient为单例可能会导致其他问题,例如旧的DNS问题。请从这里开始阅读这个长故事。


1
对于这个问题,使用HttpClientHandler并没有起作用,至少在尝试使用需要服务器管理员凭据的CouchDB API进行身份验证时没有作用。
这对我有用:
using( var client = new HttpClient() )
{
    var byteArray = Encoding.ASCII.GetBytes("MyUSER:MyPASS");
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
    ....
}

正如此处的答案所概述的那样:

如何在C#中使用HttpClient凭据?


这是与@Renè在此之上的答案相同吗?(https://dev59.com/yGs05IYBdhLWcg3wNPE3#22096194) - superjos

1

我相信这篇文章有些旧了,但是对于任何想要更新答案的人来说,当我建立我的测试服务器时,我使用了以下代码:

        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://myServer/api/Person");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            var byteArray = Encoding.ASCII.GetBytes($"{UserName}:{ApiPassword}");
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
或者这样也可以:

            using (var http = new HttpClient())
            {
                // byteArray is username:password for the server
                var byteArray = Encoding.ASCII.GetBytes("myUserName:myPassword");
                http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
                string uri = "http://myServer/api/people" ;
                var response = await http.GetStringAsync(uri);
                List<Person> agencies = JsonConvert.DeserializeObject<List<Person>>(response);
                foreach (Person person in people)
                {
                    listBox1.Items.Add(person.Name);
                }
            }

0

我刚刚下载了0.3.0版本,它已经被移除了。现在在HttpClientChannel中。

HttpClient client = new HttpClient(...);
var channel = new HttpClientChannel();
channel.Credentials = new NetworkCredential(...);
client.Channel = channel;

如果没有明确指定,它将使用默认实例的HttpClientChannel

更新:这在 .Net 4.5 中已经无效了;请参见下面的正确答案:https://dev59.com/yGs05IYBdhLWcg3wNPE3#15034995


那是旧版本吗?我正在使用来自NuGet的0.3.0版本。 - Tomas
@Thomas RSK 中的那个是原型。NuGet 版本是由另一个团队根据他们从原型中学到的重新编写的。 - Darrel Miller
@codekaizen 这个问题涉及到 .Net 4,在 .NET 4.5 发布之前就已经被提出和回答了。 - TheCodeKing
当然,我明白了。但是现在它出现在搜索结果中与同样的问题,因此提供指导当前事态是很重要的。 - codekaizen

-2

只有在指定了DefaultRequestHeaders时才能正常工作,其他方式都不行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接