设置HttpClient的授权标头

Ste*_*nes 418 c# rest oauth windows-runtime

我有一个HttpClient,我用它来使用REST API.但是,我在设置Authorization标头时遇到问题.我需要将标头设置为我从执行OAuth请求时收到的令牌.我看到.NET的一些代码表明以下内容,

httpClient.DefaultRequestHeaders.Authorization = new Credential(OAuth.token);
Run Code Online (Sandbox Code Playgroud)

但是,Credential类在WinRT中不存在.任何人有任何想法如何设置授权标头?

Ste*_*nes 725

所以这样做的方法如下,

httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "Your Oauth token");
Run Code Online (Sandbox Code Playgroud)

  • 你怎么得到"你的Oauth代币"? (13认同)
  • @kraeg,您列出的代码未编译,是否表示要像这样连接最后两个字符串:client.DefaultRequestHeaders.Add(“ Authorization”,“ Bearer” +“您的Oauth令牌”); (6认同)
  • 我的应用程序很乐意使用它多年,然后我开始得到一个RuntimeBinderException.我不得不切换到_httpClient.DefaultRequestHeaders.Add("授权","承载","你的Oauth令牌"); _再次进行. (5认同)
  • @Red fyi,第二个参数是base64编码的用户:密码(未加密). (4认同)
  • 我使用的是:client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(“ Basic”,“ encrypted user / pwd”);`从Advanced Rest Client chrome扩展名中获取加密的用户/ pwd。 (2认同)

The*_*bit 316

request.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue(
        "Basic", Convert.ToBase64String(
            System.Text.ASCIIEncoding.ASCII.GetBytes(
               $"{yourusername}:{yourpwd}")));
Run Code Online (Sandbox Code Playgroud)

  • @MickyDuncan HttpClient有一个DefaultRequestHeaders.Authorization.而这个答案只是挽救了我的一天.非常感谢WhiteRabbit. (27认同)
  • 这是行不通的,如果你检查Auhtorization标头是不包含任何超过字符串Basic. (3认同)
  • @JonathanWood因为那个;它是如何被定义使用的.Basic不提供加密,只提供足够的编码,以避免在标题中选择密码字符时出现问题. (3认同)
  • 您在这里使用ASCII编码有什么特殊原因吗?我假设使用UTF8编码没有问题,因为无论如何我们都是Base64对其进行编码。我想我想知道基本身份验证规范是否说username:password组合应该仅使用ASCII? (3认同)
  • System.Text.ASCIIEncoding.ASCII实际上是在父类Encoding中。所以你可以使用 System.Text.Encoding.ASCII 代替。 (3认同)
  • 谁能解释为什么将用户名和密码转换为 base64 字符串很重要?它不提供真正的加密,那么为什么这很重要呢? (2认同)

Wil*_*eng 76

我寻找一个处理这个问题的好方法,我正在寻找同样的问题.希望这个答案能帮助每个有同样问题的人都喜欢我.

using (var client = new HttpClient())
{
    var url = "https://www.theidentityhub.com/{tenant}/api/identity/v1";
    client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
    var response = await client.GetStringAsync(url);
    // Parse JSON response.
    ....
}
Run Code Online (Sandbox Code Playgroud)

来自https://www.theidentityhub.com/hub/Documentation/CallTheIdentityHubApi的参考

  • 你不应该在一个`using'块中放一个HttpClient.(是的,我知道它听起来倒退了,但是如果你使用`using`而不仅仅是回收HttpClient,你会泄漏连接.) (9认同)
  • 我正在做完全相同的事情@willie,但我仍然从我的 API 中得到 401 (2认同)
  • 嗨@SomethingOn我认为您没有正确的令牌密钥,所以您收到401,我将在我的个人“问问题”中分享自己的方式,希望它可以帮助您解决问题。 (2认同)

Flo*_*aal 37

我同意TheWhiteRabbit的答案,但如果你使用HttpClient进行大量调用,我认为代码似乎有点重复.

我认为有两种方法可以改善答案.

创建一个帮助程序类来创建客户端:

public static class ClientHelper
{
    // Basic auth
    public static HttpClient GetClient(string username,string password)
    {
            var authValue = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")));

            var client = new HttpClient(){
                DefaultRequestHeaders = { Authorization = authValue}
                //Set some other client defaults like timeout / BaseAddress
            };
            return client;
    }

    // Auth with bearer token
    public static HttpClient GetClient(string token)
    {
            var authValue = new AuthenticationHeaderValue("Bearer", token);

            var client = new HttpClient(){
                DefaultRequestHeaders = { Authorization = authValue}
                //Set some other client defaults like timeout / BaseAddress
            };
            return client;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

using(var client = ClientHelper.GetClient(username,password))
{
    //Perform some http call
}

using(var client = ClientHelper.GetClient(token))
{
    //Perform some http call
}
Run Code Online (Sandbox Code Playgroud)

创建扩展方法:

没有赢得美容奖,但效果很好:)

    public static class HttpClientExtentions
    {
        public static AuthenticationHeaderValue ToAuthHeaderValue(this string username, string password)
        {
            return new AuthenticationHeaderValue("Basic",
        Convert.ToBase64String(
            System.Text.Encoding.ASCII.GetBytes(
                $"{username}:{password}")));
        }
    }
Run Code Online (Sandbox Code Playgroud)

用法:

using (var client = new HttpClient())
{
    client.DefaultRequestHeaders.Authorization = _username.ToAuthHeaderValue(_password); 
}
Run Code Online (Sandbox Code Playgroud)

我再次认为上面两个选项使得客户端使用语句重复性稍差.请记住,如果您正在进行多个http调用,那么重用HttpClient是最佳做法,但我认为这个问题有点超出范围.

  • 我可以看到你的答案被upvoted但我不推荐这种方法TL; DR明显错误因为套接字耗尽,这里是解释[link](https://docs.microsoft.com/en-us/azure/architecture/反模式/不当,实例化/#问题的说明) (12认同)
  • @lacripta,这是真的,但是如果您读了最后两句话,我就是出于这个原因重用HttpClient的最佳实践,但是我认为这超出了此问题的范围。 (2认同)

Phi*_*ppe 37

因为重用HttpClient实例是一个很好的做法,对于性能和端口耗尽问题,并且因为没有一个答案给出这个解决方案(甚至引导你走向不良做法:()),我在这里给出了我所做的答案的链接在类似的问题上:

/sf/answers/2849521251/

关于如何充分利用HttpClient的一些消息来源:

  • 端口耗尽问题不是开玩笑.它几乎从未在质量保证中发生,但会在生产中遇到任何频繁使用的项目. (4认同)
  • 几乎可笑的是,这种对在客户端中设置默认身份验证的批评是如此遥远。我非常困惑为什么我需要在客户端本身上设置授权。 (3认同)

Jou*_*and 30

如果您想HttpClient使用 Bearer Token发送请求,此代码可以是一个很好的解决方案:

var requestMessage = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    Content = new StringContent(".....", Encoding.UTF8, "application/json"),
    RequestUri = new Uri(".....")
};

requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "Your token");

var response = await _httpClient.SendAsync(requestMessage);
Run Code Online (Sandbox Code Playgroud)


Jon*_*ved 23

对于现在(2021 年)发现这个旧线程的任何人,请查看此文档,了解HttpClientFactory哪些内容是可注入的,并且还将在每个请求上重新运行,以避免过期令牌,这将使其对于不记名令牌、生成的客户端、池等有用。

TL;DR:使用HttpClientFactoryand aDelegatingHandler它将充当您配置的客户端的所有传出请求的中间件。

这就是我为 Azure Identity 添加承载(由 Azure 管理)的方法,但您当然可以根据需要获取令牌;

using Microsoft.Azure.Services.AppAuthentication;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

public class BearerTokenHandler : DelegatingHandler
    {
        public BearerTokenHandler(AzureServiceTokenProvider tokenProvider, string resource)
        {
            TokenProvider = tokenProvider;
            Resource = resource;
        }

        public AzureServiceTokenProvider TokenProvider { get; }
        public string Resource { get; }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            if (!request.Headers.Contains("Authorization"))
            {
                // Fetch your token here
                string token = await TokenProvider.GetAccessTokenAsync(Resource);
                request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
            }

            return await base.SendAsync(request, cancellationToken);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我在启动中像这样配置我的类型化客户端(使用 NSwag 生成);

   var accessTokenProvider = new AzureServiceTokenProvider("<your-connection-string-for-access-token-provider>");

  builder.Services.AddHttpClient<IOrdersClient, OrdersClient>().ConfigureHttpClient(async conf =>
            {
                conf.BaseAddress = new Uri("<your-api-base-url>");
            }).AddHttpMessageHandler(() => new BearerTokenHandler(accessTokenProvider, "https://your-azure-tenant.onmicrosoft.com/api"));
Run Code Online (Sandbox Code Playgroud)

然后,您可以在任何您喜欢的地方注入 IOrdersClient,并且所有请求都将具有承载。


Ala*_*all 16

我正在设置不记名令牌

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
Run Code Online (Sandbox Code Playgroud)

它在一个端点上工作,但在另一个端点上却没有。问题是,我不得不小写b"bearer"。更改后,它现在适用于我正在使用的两个api。如果您甚至没有将它视为需要针锋相对的干草堆之一,那么就很容易错过。

确保拥有"Bearer"-拥有资本。


小智 10

使用C#HttpClient设置基本身份验证.以下代码对我有用.

   using (var client = new HttpClient())
        {
            var webUrl ="http://localhost/saleapi/api/";
            var uri = "api/sales";
            client.BaseAddress = new Uri(webUrl);
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.ConnectionClose = true;

            //Set Basic Auth
            var user = "username";
            var password = "password";
            var base64String =Convert.ToBase64String( Encoding.ASCII.GetBytes($"{user}:{password}"));
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",base64String);

            var result = await client.PostAsJsonAsync(uri, model);
            return result;
        }
Run Code Online (Sandbox Code Playgroud)


emp*_*emp 10

如果要重用HttpClient,建议不要使用 ,DefaultRequestHeaders因为它们用于随每个请求一起发送。

你可以试试这个:

var requestMessage = new HttpRequestMessage
    {
        Method = HttpMethod.Post,
        Content = new StringContent("...", Encoding.UTF8, "application/json"),
        RequestUri = new Uri("...")
    };

requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic", 
    Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes($"{user}:{password}")));

var response = await _httpClient.SendAsync(requestMessage);
Run Code Online (Sandbox Code Playgroud)

  • 是的,很难找到这个答案。我想很多人不太阅读文档,因为最佳实践是让 HttpClient 成为静态成员变量以避免端口耗尽问题。然后使用 DefaultRequestHeaders 也没有什么意义,尤其是如果我们像这里的许多人一样谈论令牌/不记名身份验证,因为这些令牌将不可避免地过期!因此,以此为基础的默认设置只是倒退。 (3认同)

Day*_*yan 9

这就是我做到的方式:

using (HttpClient httpClient = new HttpClient())
{
   Dictionary<string, string> tokenDetails = null;
   var messageDetails = new Message { Id = 4, Message1 = des };
   HttpClient client = new HttpClient();
   client.BaseAddress = new Uri("http://localhost:3774/");
   var login = new Dictionary<string, string>
       {
           {"grant_type", "password"},
           {"username", "sa@role.com"},
           {"password", "lopzwsx@23"},
       };
   var response = client.PostAsync("Token", new FormUrlEncodedContent(login)).Result;
   if (response.IsSuccessStatusCode)
   {
      tokenDetails = JsonConvert.DeserializeObject<Dictionary<string, string>>(response.Content.ReadAsStringAsync().Result);
      if (tokenDetails != null && tokenDetails.Any())
      {
         var tokenNo = tokenDetails.FirstOrDefault().Value;
         client.DefaultRequestHeaders.Add("Authorization", "Bearer " + tokenNo);
         client.PostAsJsonAsync("api/menu", messageDetails)
             .ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

这个you-tube视频帮了我很多忙.请检查一下. https://www.youtube.com/watch?v=qCwnU06NV5Q


Moh*_*ori 9

使用基本授权和Json参数.

using (HttpClient client = new HttpClient())
                    {
                        var request_json = "your json string";

                        var content = new StringContent(request_json, Encoding.UTF8, "application/json");

                        var authenticationBytes = Encoding.ASCII.GetBytes("YourUsername:YourPassword");

                        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                               Convert.ToBase64String(authenticationBytes));
                        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                        var result = await client.PostAsync("YourURL", content);

                        var result_string = await result.Content.ReadAsStringAsync();
                    }
Run Code Online (Sandbox Code Playgroud)

  • 在这样的示例中,您不应该包含禁用SSL证书检查的代码.人们可能会盲目地复制你的代码而不知道它的作用.我已经删除了那些行. (2认同)

MPJ*_*567 8

6年后,但添加此内容以防某人受到帮助。

https://www.codeproject.com/Tips/996401/Authenticate-WebAPIs-with-Basic-and-Windows-Authen

var authenticationBytes = Encoding.ASCII.GetBytes("<username>:<password>");
using (HttpClient confClient = new HttpClient())
{
  confClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", 
         Convert.ToBase64String(authenticationBytes));
  confClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(Constants.MediaType));  
  HttpResponseMessage message = confClient.GetAsync("<service URI>").Result;
  if (message.IsSuccessStatusCode)
  {
    var inter = message.Content.ReadAsStringAsync();
    List<string> result = JsonConvert.DeserializeObject<List<string>>(inter.Result);
  }
}
Run Code Online (Sandbox Code Playgroud)


Tho*_*ter 6

在 net .core 中,您可以与 Identity Server 4 一起使用

var client = new HttpClient();
client.SetBasicAuthentication(userName, password);
Run Code Online (Sandbox Code Playgroud)

或者

var client = new HttpClient();
client.SetBearerToken(token);
Run Code Online (Sandbox Code Playgroud)

请参阅https://github.com/IdentityModel/IdentityModel/blob/main/src/Client/Extensions/AuthorizationHeaderExtensions.cs

  • 第一个示例不起作用,因为默认情况下“SetBasicAuthentication()”不可用,因此它必须是扩展方法。它是在哪里定义的? (4认同)

rom*_*ros 5

UTF8选项

request.DefaultRequestHeaders.Authorization = 
new AuthenticationHeaderValue(
    "Basic", Convert.ToBase64String(
        System.Text.Encoding.UTF8.GetBytes(
           $"{yourusername}:{yourpwd}")));
Run Code Online (Sandbox Code Playgroud)


小智 5

我建议你:

HttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer <token>");
Run Code Online (Sandbox Code Playgroud)

然后可以像这样使用它:

 var response = await client.GetAsync(url);
    if (response.IsSuccessStatusCode)
    {
          responseMessage = await response.Content.ReadAsAsync<ResponseMessage>();
    }
Run Code Online (Sandbox Code Playgroud)

  • 例如,如果您的令牌每 1 小时超时,那么您必须使用此解决方案更新 HttpClient。我建议检查您的令牌是否仍然有效,否则刷新它并将其添加到 HttpRequestMessage (2认同)