我必须在对外部源的请求中使用证书。
委托处理程序包装请求API密钥的作业,然后使用API密钥发出请求。我可以将证书附加到API密钥请求并获取API密钥,但我也应该将证书附加到实际请求,但不确定如何将其附加到
InnerHandler
有人能告诉我怎么做吗?
var thumbPrint = "xxxx"; // from settings
var builder = services
.AddHttpClient("somename", c => c.BaseAddress = new Uri("someuri"))
.AddHttpMessageHandler<GatewayOAuthHandler>()
.ConfigurePrimaryMessageHandler(() => CreateHandler(GetCertificate(thumbPrint));
private X509Certificate2 GetClientCertificate(string thumbPrint)
{
var userCaStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
try
{
userCaStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var certificatesInStore = userCaStore.Certificates;
X509Certificate2 clientCertificate = null;
foreach (var certificate in certificatesInStore)
{
if (certificate.Thumbprint == thumbPrint)
{
clientCertificate = certificate;
break;
}
}
if (clientCertificate == null) throw new Exception();
return clientCertificate;
}
catch
{
throw new Exception("Certificate not found.");
}
finally
{
userCaStore.Close();
}
}
public class GatewayOAuthHandler : DelegatingHandler
{
///...
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var baseAddress = request.RequestUri.GetLeftPart(UriPartial.Authority);
var scope = request.Headers.First(kvp => kvp.Key == "scope").Value.FirstOrDefault();
string token = null;
if (request.Headers.Authorization == null)
{
token = await GetTokenResponseAsync(baseAddress, scope, cancellationToken);
if (token != null) request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode != HttpStatusCode.OK)
{
var responseStr = response.Content.ReadAsStringAsync().Result;
Logger.Log(LogLevel.Error, responseStr);
}
if (response.StatusCode != HttpStatusCode.Unauthorized) return response;
token = await RefreshTokenResponse(baseAddress, scope, cancellationToken);
if (token != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
response = await base.SendAsync(request, cancellationToken);
}
return response;
}
private async Task<string> GetTokenResponseAsync(string baseAddress, string scope, CancellationToken cancellationToken)
{
try
{
_semaphore.Wait(cancellationToken);
if (cancellationToken.IsCancellationRequested) return null;
if (!string.IsNullOrWhiteSpace(_accessToken)) return _accessToken;
_accessToken = await SendTokenRequestAsync(baseAddress, scope);
return _accessToken;
}
finally
{
_semaphore.Release();
}
}
///...
private async Task<string> SendTokenRequestAsync(string baseAddress, string scope)
{
var consumerKey = await GetSecretAsync(_settings.ConsumerKeySecretId).ConfigureAwait(false);
var consumerSecret = await GetSecretAsync(_settings.ConsumerSecretSecretId).ConfigureAwait(false);
using (var request = new HttpRequestMessage(HttpMethod.Post, TokenUri))
{
request.Content = new StringContent($"grant_type=client_credentials&scope={scope}", Encoding.UTF8, "application/x-www-form-urlencoded"); ;
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{consumerKey}:{consumerSecret}")));
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
var handler = new HttpClientHandler();
var result = await new HttpClient(handler) { BaseAddress = new Uri(baseAddress) }.SendAsync(request);
var tokenStr = await result.Content.ReadAsStringAsync();
var token = JsonConvert.DeserializeObject<JObject>(tokenStr);
return token["access_token"].ToString(); // API key
}
}
///...