我实现了一个dotnet核心API,其中端点是基于Controller属性Route定义的。
我想配置IIS,以便忽略controller 1的客户端证书,而controller 2需要客户端证书。在我的API中,我这样实现了主机
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureKestrel(o =>
{
o.ConfigureHttpsDefaults(o=>o.ClientCertificateMode=ClientCertificateMode.AllowCertificate);
})
.UseIISIntegration()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(LogLevel.Debug);
})
.UseNLog();
和配置的服务
services.AddSingleton<CertificateValidationService>();
services.Configure<IISOptions>(options =>
{
options.ForwardClientCertificate = true;
});
services.AddAuthentication()
.AddCertificate(x =>
{
x.AllowedCertificateTypes = CertificateTypes.All;
x.ValidateValidityPeriod = true;
x.RevocationMode = X509RevocationMode.NoCheck;
x.Events = new CertificateAuthenticationEvents
{
OnCertificateValidated = context =>
{
_logger.Trace("Enters OnCertificateValidated");
var validationService =
context.HttpContext.RequestServices.GetService<CertificateValidationService>();
if (validationService.ValidateCertificate(context.ClientCertificate))
{
_logger.Trace("OnCertificateValidated success");
context.Success();
}
else
{
_logger.Trace("OnCertificateValidated fail");
context.Fail("invalid certificate");
}
return Task.CompletedTask;
},
OnAuthenticationFailed = context =>
{
_logger.Trace("Enters OnAuthenticationFailed");
context.Fail("invalid certificate");
return Task.CompletedTask;
}
};
});
下面是Startup.cs的Configure方法中的中间件管道配置
if (env.IsLocal())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(appBuilder =>
{
appBuilder.Use(async (context, next) =>
{
var error = context.Features[typeof(IExceptionHandlerFeature)] as IExceptionHandlerFeature;
if (error != null && error.Error is SecurityTokenExpiredException)
{
_logger.Warn($"No valid token provided. {error.Error.Message}");
context.Response.StatusCode = 401;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
IpUrl = _globalSettings.IdP.Url,
SpName = _globalSettings.IdP.Name,
Authenticate = context.Request.GetEncodedUrl(),
//State = 401,
Msg = "Token expired"
}));
}
else if (error?.Error != null)
{
_logger.Error($"Unexpected error - {error.Error.Message}");
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
State = 500,
Msg = error.Error.Message
}));
}
else
{
await next();
}
});
});
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("AllowOrigin");
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger(SwaggerHelper.ConfigureSwagger);
app.UseSwaggerUI(SwaggerHelper.ConfigureSwaggerUi);
app.UseEndpoints(endpoints => endpoints.MapControllers());
我尝试使用web.config位置,但“路径”API/controller 2实际上并不存在(它被路由了),因此没有效果
我在app文件夹中创建了faked API/controller 2文件夹来设置SSL要求。不幸的是,我得到了一个405,因为我丢失了路由,这些文件夹后面什么都没有。
我目前唯一的方法是在API应用程序级别“接受”证书,但是,我的前端在第一次查询时,我的API会在仅使用api/controller 1时请求证书
是否有办法或必须构建和部署特定的API来保护它,而另一个API不使用客户端证书?
3条答案
按热度按时间2w3rbyxf1#
不幸的是,这是不可能的。证书验证发生在TLS层,即在实际请求到达ASP.NET核心之前,所以你不能通过路由来区分。它甚至在你实现这样的逻辑之前就失败了。
我们遇到了类似的问题,我们必须设置两个应用程序,一个有证书验证,另一个没有。有证书验证的应用程序调用另一个应用程序进行“普通”(在我们的例子中是JWT机器对机器)身份验证,并传递证书参数。
这是official docu that states this:
**我是否可以将我的应用配置为仅在某些路径上需要证书?**这是不可能的。请记住,证书交换是在HTTPS会话开始时完成的,它是由服务器在该连接上接收到第一个请求之前完成的,因此不可能基于任何请求字段来确定范围。
70gysomp2#
我也有类似的问题,我为iis express找到了一个解决方案,我认为iis也是类似的,我稍后会写这篇文章(如果它能起作用的话)。
但是关于溶液(起始条件):
1.我在舞台上测试从视觉工作室,我运行下集成在VS的iis表达净核心应用程序。
1.对于我的解决方案,我需要请求用户证书时,用户转到URL "/证书/应用/"(仅在此页面上)。
1.项目名称为"TestCore"
步骤:
1.在visual studio项目文件夹中,您需要找到隐藏文件夹. vs,在此文件夹中,您需要找到文件夹"config"和文件"applicationhost. config"
1.在此文件中,您需要找到与以下部分类似的项目配置:
1.在文件中克隆(复制-粘贴)此节并修改副本(更改路径并添加sequryti节):
1.尝试启动项目(对于mee,它工作正常).
我希望我(或其他人)会找到同样的方式为IIS。
7d7tgy0s3#
对于IIS和IISExpress,这可以通过使用location元素来实现,我已经成功地使用了它,如下所示(这是添加在web.config中的configuration元素中的-请参阅here中的示例):
这意味着除restapi之外的任何路由,例如http://localhost/whatever,服务器将不要求客户端证书作为请求的一部分。一旦您点击http://localhost/restapi/whatever 2,就需要客户端证书(如果您从浏览器调用此命令,您将看到一个弹出窗口,要求您选择要发布的客户端证书)。
对于Kestrel,请查看Maxim Zabolotskikh提供的answer。