我有一个HttpClient,我正在使用一个REST API。但是,我在设置授权标头时遇到了麻烦。我需要将标头设置为我从执行OAuth请求中接收到的令牌。 我看到了一些。net的代码,建议如下:

httpClient.DefaultRequestHeaders.Authorization = new Credential(OAuth.token);

然而,凭据类在WinRT中不存在。有人知道如何设置授权头吗?


当前回答

使用基本授权和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();
}

其他回答

使用基本授权和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();
}

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

var client = new HttpClient();
client.SetBasicAuthentication(userName, password);

or

var client = new HttpClient();
client.SetBearerToken(token);

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

use UTF8选项

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

我偶然发现了这条旧线索。我遇到的问题是我知道使用静态HttpClient,但是我的令牌需要每59分钟刷新一次。

所以我可以使用HttpClientFactory,但是因为我的一个项目仍然在. net 4.8中,我创建了一个从HttpClient继承的类,所以我在所有项目中都有类似的代码。需要一个秘密才能获得令牌(我使用identityserver4)。

然后我将它设置为DI中的单例(我在这里使用Ninject):

Bind<MyHttpClient>().ToMethod(c =>
{
    var accessKey = ConfigurationManager.AppSettings["AccessKey"];

    var client = new MyHttpClient(accessKey)
    {
        BaseAddress = new Uri(MyUrls.MyApiBaseUrl)
    };

    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

    return client;
}).InSingletonScope();

然后是类本身——以它用来访问的API命名:

public class MyHttpClient : BaseHttpClient
{
     private static readonly HttpClient _authHttpClient = new HttpClient();
     private string _secret;

     public MyHttpClient(string secret)
     {
         _secret = secret;
     }

    /// <summary>
    /// Add the token to each and every request, cached for 1 minute less than the token's lifetime
    /// </summary>
    /// <param name="request"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var cacheSeconds = 3600 - 60; // Default of 59 minutes

        var token = CacheHelper<string>.Get("MyToken", cacheSeconds * 60, () =>
        {
            var authorityUrl = MyUrls.AuthServerUrl;

            // discover endpoints from metadata
            DiscoveryDocumentResponse disco;
            disco = _authHttpClient.GetDiscoveryDocumentAsync(authorityUrl).Result;
            if (disco.IsError)
            {
                throw new Exception("Error getting discovery document: " + disco.Error);
            }

            // request token
            var tokenResponse = _authHttpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,

                ClientId = "myapp",
                ClientSecret = _secret,
                Scope = "myapi"
            }).Result;

            if (tokenResponse.IsError)
            {
                throw new Exception("Error getting token: " + tokenResponse.Error);
            }

            if (tokenResponse.ExpiresIn < cacheSeconds + 60)
            {
                throw new Exception($"Token expires in {tokenResponse.ExpiresIn}s, which is less than {cacheSeconds + 60}");
            }

            if (tokenResponse.ExpiresIn > cacheSeconds + 60)
            {
                Log.Warn().Message($"Token expiry in {tokenResponse.ExpiresIn}s, which is greater than {cacheSeconds}").Write();
            }

            return tokenResponse.AccessToken;
        });

        // THIS IS THE BIT - Assign this inside a SendAsync override and you are done!
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return base.SendAsync(request, cancellationToken);
    }

}

最后为了完整起见,我的CacheHelper类看起来是这样的:

public static class CacheHelper<T>
{
    private static readonly object _locker = new object();

    public static T Get(string cacheName, int cacheTimeoutSeconds, Func<T> func)
    {
        var obj = MemoryCache.Default.Get(cacheName, null);
        if (obj != null) return (T)obj;

        lock (_locker)
        {
            obj = MemoryCache.Default.Get(cacheName, null);
            if (obj == null)
            {
                obj = func();
                var cip = new CacheItemPolicy
                {
                    AbsoluteExpiration = new DateTimeOffset(DateTime.UtcNow.AddSeconds(cacheTimeoutSeconds))
                };
                MemoryCache.Default.Set(cacheName, obj, cip);
            }
        }

        return (T)obj;
    }
}

方法是这样的,

httpClient.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", "Your Oauth token");