我正在尝试使用客户端证书针对ASP.NET Core 3.1 WebService进行身份验证。 该项目是使用IIS Express在VS2019 v16.6.2中启动的。
如果我以可执行文件形式启动项目,则一切正常:通过HttpClientHandler
或在标头中设置客户端证书身份验证。
但是,在IIS Express中启动项目时,仅在标头中设置的客户端证书身份验证有效。在调用HttpClientHandler
时,在X509Certificate2
中设置客户端证书会导致空Request.HttpContext.Connection.GetClientCertificateAsync().Result
。
我正在使用一个自签名证书,并且证书链在我的本地证书存储中(包括自签名根证书)。
没有一个证书定义了certificate revocation list
,简称:CRL
。
可能与此有关,但是我在该方向上尝试的一切都死胡同,我不知道该怎么做。
我的Program.cs
包含以下内容:
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>()
.ConfigureKestrel(options =>
{
var cert = new X509Certificate2(Path.Combine(@"[some path]\ServerCertificate.pfx"), "[password]");
options.ConfigureHttpsDefaults(o =>
{
o.ServerCertificate = cert;
o.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
});
});
});
和ConfigureServices(IServiceCollection services)
中的函数Startup.cs
services.AddSingleton<MyCertificateValidationService>();
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options => // code from ASP.NET Core sample
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.RevocationMode = X509RevocationMode.NoCheck;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService =
context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer),
new Claim(ClaimTypes.Name, context.ClientCertificate.Subject, ClaimValueTypes.String, context.Options.ClaimsIssuer)
};
context.Principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name));
context.Success();
}
else
{
context.Fail("invalid cert");
}
return Task.CompletedTask;
}
};
});
services.AddCertificateForwarding(options =>
{
options.CertificateHeader = "X-ARR-ClientCert";
options.HeaderConverter = (headerValue) =>
{
X509Certificate2 clientCertificate = null;
if (!string.IsNullOrWhiteSpace(headerValue))
{
byte[] bytes = StringToByteArray(headerValue);
clientCertificate = new X509Certificate2(bytes);
}
return clientCertificate;
};
});
services.AddAuthorization();
services.AddControllers();
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
在Configure
中我定义
app.UseHttpsRedirection();
app.UseRouting();
app.UseCertificateForwarding();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
我有主叫方
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(cert);
handler.CheckCertificateRevocationList = false;
handler.ServerCertificateCustomValidationCallback =
(httpRequestMessage, serverCert, cetChain, policyErrors) =>
{
return true;
};
var client = new HttpClient(handler);
var request = new HttpRequestMessage()
{
RequestUri = new Uri("https://localhost:44312/viewer/test"),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
激活applicationhost.config
中的IIS日志,我得到一个日志文件说明
#Software: Microsoft Internet Information Services 10.0
#Version: 1.0
#Date: 2020-06-23 19:05:07
#Fields: date time s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent) cs(Referer) sc-status sc-substatus sc-win32-status time-taken
2020-06-23 19:05:07 ::1 GET /weatherforecast - 44312 - ::1 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64;+rv:77.0)+Gecko/20100101+Firefox/77.0 - 200 0 0 1990
2020-06-23 19:05:25 ::1 GET /viewer/test - 44312 - ::1 - - 403 0 0 14
和一个带有4303行的另一个xml日志文件,指出403返回了我无法识别问题的位置(如果它写在其中)。
如何使IIS Express通过客户端证书而不将其设置为null?