c# - HttpContext.RequestServices.GetService<>() 返回的证书验证服务为空
问题描述
我正在尝试关注在 ASP.NET Core 中演示证书身份验证的Microsoft 文档和其他博客。调用 RequestServices.GetService() 返回 null。我在validationService 变量上添加了空检查,以检查它是空引用。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
{
options.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();
if (validationService == null)
{
throw new NullReferenceException("Validation Service returned by GetService<MyCertificateValidationService>() is null");
}
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();
}
return Task.CompletedTask;
}
};
});
services.AddControllers();
services.AddMvc()
.AddXmlSerializerFormatters();
}
验证服务类:
public class MyCertificateValidationService
{
public bool ValidateCertificate(X509Certificate2 clientCertificate)
{
bool valid = false;
var cert = new X509Certificate2(Path.Combine("Test.crt"), ")F@4R9df3s75(5g0");
if (clientCertificate.Thumbprint == cert.Thumbprint)
{
valid = true;
}
return valid;
}
}
下面是 Startup 中的 Configure 方法:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCertificateForwarding();
app.UseAuthentication();
loggerFactory.AddSerilog();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
app.UseMiddleware<SerilogMiddleware>();
app.UseMiddleware<AuthenticationMiddleware>();
app.UseRouting();
app.UseEndpoints(endPoints =>
{
endPoints.MapControllers();
});
}
解决方案
正如 king king 所说,如果你想使用自定义证书处理服务,你应该先注册它,然后像下面这样使用它:
注意:文档中提到你也可以使用,如果你想从方法ICertificateValidationService
中获取它,你还需要自己构建这个服务并将它注册为服务。context.HttpContext.RequestServices.GetService
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<MyCertificateValidationService>();
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate(options =>
{
options.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
options.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
var validationService = context.HttpContext.RequestServices.GetService<MyCertificateValidationService>();
if (validationService == null)
{
throw new NullReferenceException("Validation Service returned by GetService<MyCertificateValidationService>() is null");
}
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();
}
return Task.CompletedTask;
}
};
});
services.AddControllers();
services.AddMvc()
.AddXmlSerializerFormatters();
}
另外我建议您可以参考这个github 演示以了解它如何与客户端证书身份验证一起使用。
推荐阅读
- sql - Scala 模式匹配 - 识别 Java.Sql 中的连接(基础设施)异常和数据(查询)异常
- mongodb - $MongoDB $lookup foreach 同一集合上数组中的元素
- python - 从两个 numpy 数组中创建一个新数组
- datetime - 如何使用 jest 将带有 Date 的 expect.toMatchObject() 作为预期属性值之一传递?
- powerbi - Power BI - 使用参考表进行合并
- c - 是否可以检查两个指针是否指向同一个对象?
- node.js - 使用已启动并正在运行的 Robo3t 找不到我的 mongo 数据库
- python - Pandas - 如何用范围时间条件填充列
- spring-batch - 在 SpringBatch 中使用 ClassifierCompositeItemProcessor 时,通过 StepBuilderFactory stream() 将文件名动态传递给 FlatFileItemWriter
- awk - 如何使用awk或正则表达式过滤日志